@seekbuddy/dsh-ui 0.0.0-stage → 0.2.0-beta.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 (195) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +22 -0
  3. package/README.md +175 -2
  4. package/README.zh.md +176 -0
  5. package/THIRD_PARTY_NOTICES.md +42 -0
  6. package/UPSTREAM.md +56 -0
  7. package/dist/blocks.js +1582 -0
  8. package/dist/chunks/chunk-23KOEBWJ.js +104 -0
  9. package/dist/chunks/chunk-3HCOU44R.js +697 -0
  10. package/dist/chunks/chunk-5JXG4BHW.js +31 -0
  11. package/dist/chunks/chunk-5XDVPALS.js +61 -0
  12. package/dist/chunks/chunk-AY44MQMD.js +3052 -0
  13. package/dist/chunks/chunk-B3EEK7A2.js +408 -0
  14. package/dist/chunks/chunk-CEBTQO6W.js +24 -0
  15. package/dist/chunks/chunk-CI73NXA5.js +202 -0
  16. package/dist/chunks/chunk-CTQPGUZP.js +22 -0
  17. package/dist/chunks/chunk-F352IICS.js +57 -0
  18. package/dist/chunks/chunk-IOBKTEKP.js +144 -0
  19. package/dist/chunks/chunk-KETGFAOH.js +66 -0
  20. package/dist/chunks/chunk-LA3QDZYN.js +2777 -0
  21. package/dist/chunks/chunk-NE62SYOZ.js +89 -0
  22. package/dist/chunks/chunk-OQPH36OI.js +754 -0
  23. package/dist/chunks/chunk-QJKAQ6PO.js +155 -0
  24. package/dist/chunks/chunk-R6AUJQ3G.js +129 -0
  25. package/dist/chunks/chunk-RNVSCTW7.js +24 -0
  26. package/dist/chunks/chunk-RZOP2PFC.js +152 -0
  27. package/dist/chunks/chunk-TQU54HSM.js +112 -0
  28. package/dist/chunks/chunk-TUK6UGXM.js +36 -0
  29. package/dist/chunks/chunk-TZ7HRE6D.js +328 -0
  30. package/dist/chunks/chunk-VIH56PDF.js +57 -0
  31. package/dist/chunks/chunk-WUL523OW.js +27 -0
  32. package/dist/chunks/chunk-XX6MSZLS.js +261 -0
  33. package/dist/chunks/chunk-ZA47FP7C.js +7 -0
  34. package/dist/chunks/chunk-ZZNL5PWF.js +170 -0
  35. package/dist/icons.js +803 -0
  36. package/dist/index.js +1182 -0
  37. package/dist/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  38. package/dist/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  39. package/dist/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  40. package/dist/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  41. package/dist/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  42. package/dist/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  43. package/dist/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  44. package/dist/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  45. package/dist/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  46. package/dist/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  47. package/dist/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  48. package/dist/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  49. package/dist/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  50. package/dist/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  51. package/dist/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  52. package/dist/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  53. package/dist/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  54. package/dist/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  55. package/dist/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  56. package/dist/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  57. package/dist/katex.css +1 -0
  58. package/dist/katex.css.d.ts +2 -0
  59. package/dist/markdown.js +148 -0
  60. package/dist/meta.json +6876 -0
  61. package/dist/root-inputs.json +67 -0
  62. package/dist/seekbuddy-card.js +7 -0
  63. package/dist/seekbuddy-empty.js +8 -0
  64. package/dist/seekbuddy-internal/DangerButton.js +7 -0
  65. package/dist/seekbuddy-internal/Mark.js +7 -0
  66. package/dist/seekbuddy-internal/Message.js +10 -0
  67. package/dist/seekbuddy-internal/Pagination.js +9 -0
  68. package/dist/seekbuddy-internal/StatusBadge.js +7 -0
  69. package/dist/seekbuddy-internal/SubtleButton.js +7 -0
  70. package/dist/seekbuddy-internal/Switch.js +7 -0
  71. package/dist/seekbuddy-internal/Upload.js +7 -0
  72. package/dist/seekbuddy-internal/date/Calendar.js +8 -0
  73. package/dist/seekbuddy-internal/date/DatePicker.js +9 -0
  74. package/dist/seekbuddy-internal/date/DateRangePicker.js +9 -0
  75. package/dist/seekbuddy-internal/date/TimePicker.js +8 -0
  76. package/dist/seekbuddy-internal/date/fields.js +16 -0
  77. package/dist/seekbuddy-internal/qr/QrCode.js +7 -0
  78. package/dist/seekbuddy-spinner.js +7 -0
  79. package/dist/seekbuddy-tabs.js +7 -0
  80. package/dist/seekbuddy-timeline.js +8 -0
  81. package/dist/seekbuddy.js +89 -0
  82. package/dist/theme-bootstrap.js +13 -0
  83. package/dist/theme.js +37 -0
  84. package/dist/tokens.css +934 -0
  85. package/dist/tokens.css.d.ts +2 -0
  86. package/dist/types/Button.d.ts +18 -0
  87. package/dist/types/Checkbox.d.ts +19 -0
  88. package/dist/types/CodeFileIcon.d.ts +11 -0
  89. package/dist/types/CodeToolbar.d.ts +29 -0
  90. package/dist/types/ConfigField.d.ts +32 -0
  91. package/dist/types/ConnectionIndicator.d.ts +25 -0
  92. package/dist/types/DiffBlock.d.ts +51 -0
  93. package/dist/types/DisclosureRow.d.ts +35 -0
  94. package/dist/types/FileTypeIcon.d.ts +42 -0
  95. package/dist/types/FoldToggle.d.ts +19 -0
  96. package/dist/types/HoverCard.d.ts +36 -0
  97. package/dist/types/ImageLightbox.d.ts +26 -0
  98. package/dist/types/ImagePreview.d.ts +11 -0
  99. package/dist/types/Input.d.ts +11 -0
  100. package/dist/types/JsonTree.d.ts +58 -0
  101. package/dist/types/LinkIcon.d.ts +33 -0
  102. package/dist/types/Menu.d.ts +142 -0
  103. package/dist/types/MenuGroup.d.ts +21 -0
  104. package/dist/types/MenuSurface.d.ts +15 -0
  105. package/dist/types/Modal.d.ts +43 -0
  106. package/dist/types/PermissionIcon.d.ts +38 -0
  107. package/dist/types/Pill.d.ts +12 -0
  108. package/dist/types/ReadBlock.d.ts +47 -0
  109. package/dist/types/ReferenceIcon.d.ts +20 -0
  110. package/dist/types/RiskConfirmation.d.ts +19 -0
  111. package/dist/types/SearchBlock.d.ts +71 -0
  112. package/dist/types/SegmentedControl.d.ts +34 -0
  113. package/dist/types/SegmentedTabs.d.ts +25 -0
  114. package/dist/types/ShortcutKeys.d.ts +10 -0
  115. package/dist/types/SiteGlyph.d.ts +24 -0
  116. package/dist/types/StateDot.d.ts +19 -0
  117. package/dist/types/Switch.d.ts +19 -0
  118. package/dist/types/Tag.d.ts +31 -0
  119. package/dist/types/TerminalBlock.d.ts +77 -0
  120. package/dist/types/TextShimmer.d.ts +22 -0
  121. package/dist/types/Toast.d.ts +48 -0
  122. package/dist/types/Tooltip.d.ts +63 -0
  123. package/dist/types/WebBlock.d.ts +60 -0
  124. package/dist/types/ansi.d.ts +16 -0
  125. package/dist/types/blocks.d.ts +19 -0
  126. package/dist/types/clipboard.d.ts +8 -0
  127. package/dist/types/code-file-icon-artwork.d.ts +53 -0
  128. package/dist/types/code-file-types.d.ts +29 -0
  129. package/dist/types/code-highlighting.d.ts +11 -0
  130. package/dist/types/css-modules.d.ts +6 -0
  131. package/dist/types/darwin-desktop.d.ts +8 -0
  132. package/dist/types/file-size.d.ts +7 -0
  133. package/dist/types/focus.d.ts +8 -0
  134. package/dist/types/guide-artwork.d.ts +14 -0
  135. package/dist/types/head-tail-cap.d.ts +22 -0
  136. package/dist/types/icons/index.d.ts +384 -0
  137. package/dist/types/icons/props.d.ts +8 -0
  138. package/dist/types/icons/shared-artwork.d.ts +42 -0
  139. package/dist/types/icons.d.ts +6 -0
  140. package/dist/types/index.d.ts +53 -0
  141. package/dist/types/input-modality.d.ts +18 -0
  142. package/dist/types/keyboard-composition.d.ts +10 -0
  143. package/dist/types/markdown/CodeBlock.d.ts +34 -0
  144. package/dist/types/markdown/JsonBlock.d.ts +7 -0
  145. package/dist/types/markdown/MarkdownDelegate.d.ts +45 -0
  146. package/dist/types/markdown/MarkdownText.d.ts +47 -0
  147. package/dist/types/markdown/cjkFriendlyStrong.d.ts +8 -0
  148. package/dist/types/markdown/file-link.d.ts +12 -0
  149. package/dist/types/markdown/highlight.d.ts +147 -0
  150. package/dist/types/markdown/incremental.d.ts +79 -0
  151. package/dist/types/markdown/katex.d.ts +18 -0
  152. package/dist/types/markdown/local-image-syntax.d.ts +9 -0
  153. package/dist/types/markdown/mathCompatibility.d.ts +10 -0
  154. package/dist/types/markdown/parse.d.ts +24 -0
  155. package/dist/types/markdown/plain-text.d.ts +21 -0
  156. package/dist/types/markdown/render.d.ts +140 -0
  157. package/dist/types/markdown/useViewportHighlighting.d.ts +10 -0
  158. package/dist/types/markdown.d.ts +9 -0
  159. package/dist/types/overlay-top-margin.d.ts +7 -0
  160. package/dist/types/plugin-artwork.d.ts +16 -0
  161. package/dist/types/pointer-grace.d.ts +21 -0
  162. package/dist/types/rank-by-name.d.ts +21 -0
  163. package/dist/types/relative-time.d.ts +22 -0
  164. package/dist/types/seekbuddy/Card.d.ts +28 -0
  165. package/dist/types/seekbuddy/DangerButton.d.ts +31 -0
  166. package/dist/types/seekbuddy/Empty.d.ts +34 -0
  167. package/dist/types/seekbuddy/Mark.d.ts +27 -0
  168. package/dist/types/seekbuddy/Message.d.ts +52 -0
  169. package/dist/types/seekbuddy/Pagination.d.ts +66 -0
  170. package/dist/types/seekbuddy/Spinner.d.ts +20 -0
  171. package/dist/types/seekbuddy/StatusBadge.d.ts +33 -0
  172. package/dist/types/seekbuddy/SubtleButton.d.ts +30 -0
  173. package/dist/types/seekbuddy/Switch.d.ts +36 -0
  174. package/dist/types/seekbuddy/Tabs.d.ts +49 -0
  175. package/dist/types/seekbuddy/Timeline.d.ts +42 -0
  176. package/dist/types/seekbuddy/Upload.d.ts +101 -0
  177. package/dist/types/seekbuddy/date/Calendar.d.ts +94 -0
  178. package/dist/types/seekbuddy/date/DatePicker.d.ts +29 -0
  179. package/dist/types/seekbuddy/date/DateRangePicker.d.ts +41 -0
  180. package/dist/types/seekbuddy/date/TimePicker.d.ts +35 -0
  181. package/dist/types/seekbuddy/date/date.d.ts +79 -0
  182. package/dist/types/seekbuddy/date/fields.d.ts +45 -0
  183. package/dist/types/seekbuddy/index.d.ts +49 -0
  184. package/dist/types/seekbuddy/qr/QrCode.d.ts +37 -0
  185. package/dist/types/seekbuddy/qr/qr.d.ts +38 -0
  186. package/dist/types/theme-bootstrap.d.ts +3 -0
  187. package/dist/types/theme-core.d.ts +14 -0
  188. package/dist/types/theme.d.ts +4 -0
  189. package/dist/types/use-copy-feedback.d.ts +13 -0
  190. package/dist/types/useAnchoredMaxHeight.d.ts +13 -0
  191. package/dist/types/useAnchoredPosition.d.ts +35 -0
  192. package/dist/types/useDismissOnOutsidePointer.d.ts +10 -0
  193. package/dist/types/useModalLayer.d.ts +26 -0
  194. package/dist/types/user-text.d.ts +36 -0
  195. package/package.json +151 -4
package/dist/blocks.js ADDED
@@ -0,0 +1,1582 @@
1
+ import {
2
+ Menu,
3
+ Pill,
4
+ StateDot
5
+ } from "./chunks/chunk-3HCOU44R.js";
6
+ import {
7
+ CodeCard_module_default,
8
+ CodeToolbar,
9
+ FileTypeIcon,
10
+ LinkIconMedium,
11
+ LinkIconRegular,
12
+ MarkdownText,
13
+ classifyFileType,
14
+ classifyLinkPath,
15
+ fileExtension,
16
+ grammarLoadCount,
17
+ highlightLines,
18
+ subscribeGrammarLoaded,
19
+ useViewportHighlighting
20
+ } from "./chunks/chunk-AY44MQMD.js";
21
+ import {
22
+ writeClipboard
23
+ } from "./chunks/chunk-OQPH36OI.js";
24
+ import {
25
+ IconCheckOutlineRegular,
26
+ IconCopyOutlineRegular,
27
+ IconWrapLinesOutlineRegular
28
+ } from "./chunks/chunk-LA3QDZYN.js";
29
+ import "./chunks/chunk-ZA47FP7C.js";
30
+
31
+ // src/JsonTree.tsx
32
+ import clsx from "clsx";
33
+ import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
34
+
35
+ // .build/css/JsonTree.module.mjs
36
+ var id = "@seekbuddy/dsh-ui/JsonTree.module.css";
37
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id + '"]')) {
38
+ const element = document.createElement("style");
39
+ element.setAttribute("data-dsh-ui-primitives", id);
40
+ element.textContent = '.vOc5Ca_root{--json-tree-property:#881391;--json-tree-string:#c41a16;--json-tree-number:#1c00cf;--json-tree-keyword:#1c00cf;--json-tree-punctuation:#202124;--json-tree-icon:#5f6368;--json-tree-hover:#3c40430a;min-width:0;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);font:12px/16px var(--ds-font-family-code);overscroll-behavior-x:contain;overscroll-behavior-y:auto;position:relative;overflow:auto}body[data-ds-dark-theme] .vOc5Ca_root{--json-tree-property:#5db0d7;--json-tree-string:#f28b82;--json-tree-number:#99c8ff;--json-tree-keyword:#99c8ff;--json-tree-punctuation:#e8eaed;--json-tree-icon:#9aa0a6;--json-tree-hover:#e8eaed0d}.vOc5Ca_container{box-sizing:border-box;white-space:pre;width:100%;min-width:0;margin:0;padding:6px 8px 8px}.vOc5Ca_expandedTopLevel{box-sizing:border-box;width:100%;min-width:0;padding:6px 8px 8px 14px}.vOc5Ca_expandedTopLevel:has(>.vOc5Ca_topLevelBracket[data-json-root-row]:hover),.vOc5Ca_expandedTopLevel:has(>.vOc5Ca_topLevelBracket[data-json-root-row][data-json-copy-active]){background:var(--json-tree-hover)}.vOc5Ca_expandedTopLevelContainer{padding:0}.vOc5Ca_row.vOc5Ca_topLevelBracket{margin-left:0;padding-left:0}.vOc5Ca_children{margin:0;padding:0;list-style:none}.vOc5Ca_row{box-sizing:border-box;overflow-wrap:anywhere;white-space:pre-wrap;min-width:0;min-height:16px;margin:0;padding:0 0 0 10px;list-style:none;position:relative}.vOc5Ca_row:not(.vOc5Ca_topLevelBracket):hover:not(:has(.vOc5Ca_row:hover)):after,.vOc5Ca_row:not(.vOc5Ca_topLevelBracket)[data-json-copy-active]:after,.vOc5Ca_row:has(>.vOc5Ca_expander:focus-visible):after{z-index:0;height:var(--json-tree-row-height,16px);background:var(--json-tree-hover);content:"";pointer-events:none;position:absolute;top:0;left:0;right:0}.vOc5Ca_row>span:not(.vOc5Ca_expander,.vOc5Ca_copySlot){z-index:1;position:relative}.vOc5Ca_label{color:var(--json-tree-property);margin-right:3px;font-weight:400}.vOc5Ca_clickableLabel{cursor:pointer}.vOc5Ca_stringValue{color:var(--json-tree-string)}.vOc5Ca_stringField{z-index:1;display:flow-root;position:relative}.vOc5Ca_stringText{max-height:calc(var(--json-tree-collapsed-lines) * 16px);text-indent:-12px;word-break:break-all;padding-left:12px;display:block;overflow:hidden}.vOc5Ca_stringRaw{color:var(--dsw-alias-label-primary);font:inherit;overflow-wrap:normal;white-space:pre;word-break:normal;margin:4px 0 0 12px;overflow:auto}.vOc5Ca_stringActions{justify-content:flex-end;align-items:center;gap:4px;width:fit-content;height:16px;display:flex;position:absolute;top:1px;right:4px}.vOc5Ca_stringRaw[data-wrap=true]{overflow-wrap:anywhere;white-space:pre-wrap;word-break:break-all}.vOc5Ca_stringActions>.vOc5Ca_copySlot{opacity:1;pointer-events:auto}.vOc5Ca_stringToggleSlot{float:right;height:calc(var(--json-tree-collapsed-lines) * 16px);shape-outside:inset(calc((var(--json-tree-collapsed-lines) - 1) * 16px) 0 0);pointer-events:none;align-items:flex-end;margin-left:2px;display:flex}.vOc5Ca_stringToggle{color:var(--dsw-alias-label-secondary);font:inherit;text-indent:0;white-space:nowrap;cursor:pointer;pointer-events:auto;background:0 0;border:0;align-items:baseline;gap:2px;margin:0;padding:0;display:inline-flex}.vOc5Ca_stringToggle:hover{color:var(--dsw-alias-label-primary)}.vOc5Ca_stringToggle:focus-visible{outline:1px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}.vOc5Ca_row:has(>.vOc5Ca_stringField){--json-tree-row-height:100%}.vOc5Ca_summary{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.vOc5Ca_numberValue{color:var(--json-tree-number)}.vOc5Ca_keywordValue{color:var(--json-tree-keyword)}.vOc5Ca_otherValue{color:var(--dsw-alias-label-secondary)}.vOc5Ca_punctuation,.vOc5Ca_preview,.vOc5Ca_previewProperty{color:var(--json-tree-punctuation)}.vOc5Ca_previewEllipsis{color:var(--dsw-alias-label-tertiary)}.vOc5Ca_copySlot{opacity:0;pointer-events:none;width:20px;height:16px;display:inline-flex}.vOc5Ca_row>.vOc5Ca_copySlot{z-index:2;position:absolute;top:0;right:0}.vOc5Ca_row:has(>.vOc5Ca_stringField)>.vOc5Ca_copySlot{top:auto;bottom:0}.vOc5Ca_row:has(>.vOc5Ca_copySlot)>.vOc5Ca_stringField .vOc5Ca_stringToggleSlot{padding-right:24px}.vOc5Ca_row:hover:not(:has(.vOc5Ca_row:hover))>.vOc5Ca_copySlot,.vOc5Ca_row[data-json-copy-active]>.vOc5Ca_copySlot,.vOc5Ca_copySlot:focus-within{opacity:1;pointer-events:auto}.vOc5Ca_actionButton{box-sizing:border-box;border-radius:var(--dsw-radius-xs);width:20px;height:16px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}.vOc5Ca_actionButton:hover{color:var(--dsw-alias-label-primary)}.vOc5Ca_actionButton[aria-pressed=true]{color:var(--dsw-alias-state-business-primary)}.vOc5Ca_actionButton:focus-visible{outline:1px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-1px}.vOc5Ca_actionButton[data-state=failed]{color:var(--dsw-alias-state-error-primary)}.vOc5Ca_expander{z-index:2;box-sizing:border-box;width:8px;height:16px;color:var(--json-tree-icon);cursor:pointer;user-select:none;justify-content:flex-start;align-items:center;margin:0;display:inline-flex;position:absolute;top:0;left:0}.vOc5Ca_expander:before{content:"";transform-origin:33.333%;border-top:4px solid #0000;border-bottom:4px solid #0000;border-left:6px solid;width:0;height:0;transform:scale(.75)}.vOc5Ca_collapseIcon:before{transform:rotate(90deg)scale(.75)}.vOc5Ca_expander:hover{color:var(--dsw-alias-label-primary)}.vOc5Ca_expander:focus-visible{outline:none}.vOc5Ca_collapsedContent{color:var(--json-tree-punctuation);cursor:pointer;margin:0 1px}.vOc5Ca_collapsedContent:after{content:"\u2026"}';
41
+ document.head.appendChild(element);
42
+ }
43
+ var JsonTree_module_default = { "punctuation": "vOc5Ca_punctuation", "stringField": "vOc5Ca_stringField", "expander": "vOc5Ca_expander", "collapsedContent": "vOc5Ca_collapsedContent", "stringToggleSlot": "vOc5Ca_stringToggleSlot", "topLevelBracket": "vOc5Ca_topLevelBracket", "stringValue": "vOc5Ca_stringValue", "expandedTopLevelContainer": "vOc5Ca_expandedTopLevelContainer", "previewProperty": "vOc5Ca_previewProperty", "actionButton": "vOc5Ca_actionButton", "container": "vOc5Ca_container", "children": "vOc5Ca_children", "expandedTopLevel": "vOc5Ca_expandedTopLevel", "keywordValue": "vOc5Ca_keywordValue", "previewEllipsis": "vOc5Ca_previewEllipsis", "stringToggle": "vOc5Ca_stringToggle", "root": "vOc5Ca_root", "collapseIcon": "vOc5Ca_collapseIcon", "stringText": "vOc5Ca_stringText", "summary": "vOc5Ca_summary", "label": "vOc5Ca_label", "preview": "vOc5Ca_preview", "stringActions": "vOc5Ca_stringActions", "otherValue": "vOc5Ca_otherValue", "copySlot": "vOc5Ca_copySlot", "clickableLabel": "vOc5Ca_clickableLabel", "stringRaw": "vOc5Ca_stringRaw", "row": "vOc5Ca_row", "numberValue": "vOc5Ca_numberValue" };
44
+
45
+ // src/JsonTree.tsx
46
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
47
+ var OBJECT_PREVIEW_LIMIT = 4;
48
+ var ARRAY_PREVIEW_LIMIT = 5;
49
+ var PREVIEW_DEPTH_LIMIT = 2;
50
+ function valueCopyMenuItems(labels) {
51
+ return [
52
+ { id: "value", label: labels.copyValue },
53
+ { id: "json", label: labels.copyJson },
54
+ { id: "path", label: labels.copyPath }
55
+ ];
56
+ }
57
+ function objectCopyMenuItems(labels) {
58
+ return [
59
+ { id: "prettyJson", label: labels.copyPrettyJson },
60
+ { id: "json", label: labels.copyCompactJson },
61
+ { id: "path", label: labels.copyPath }
62
+ ];
63
+ }
64
+ function createCopyStore() {
65
+ let current;
66
+ const listeners = /* @__PURE__ */ new Map();
67
+ return {
68
+ get: () => current,
69
+ set(next) {
70
+ const previous = current?.id;
71
+ current = next;
72
+ for (const id7 of /* @__PURE__ */ new Set([previous, next?.id])) {
73
+ if (id7 === void 0) continue;
74
+ for (const listener of listeners.get(id7) ?? []) listener();
75
+ }
76
+ },
77
+ subscribe(id7, listener) {
78
+ let row = listeners.get(id7);
79
+ if (row === void 0) listeners.set(id7, row = /* @__PURE__ */ new Set());
80
+ row.add(listener);
81
+ return () => {
82
+ row.delete(listener);
83
+ if (row.size === 0) listeners.delete(id7);
84
+ };
85
+ }
86
+ };
87
+ }
88
+ function JsonCopyAction({
89
+ store,
90
+ target,
91
+ persistent,
92
+ labels,
93
+ onCopy,
94
+ onClose
95
+ }) {
96
+ const id7 = pathId(target.path);
97
+ const subscribe = useCallback((listener) => store.subscribe(id7, listener), [id7, store]);
98
+ const getSnapshot = () => {
99
+ const current = store.get();
100
+ return current?.id === id7 ? current : void 0;
101
+ };
102
+ const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
103
+ const buttonRef = useRef(null);
104
+ const state = snapshot?.state ?? "idle";
105
+ const object = typeof target.value === "object" && target.value !== null;
106
+ const copyTitle = state === "copied" ? labels.copied : state === "failed" ? labels.copyFailed : object ? labels.copyPrettyJson : labels.copyValue;
107
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.copySlot, children: (persistent || snapshot !== void 0) && /* @__PURE__ */ jsx(
108
+ Menu,
109
+ {
110
+ open: snapshot?.menuOpen === true,
111
+ compact: true,
112
+ portal: true,
113
+ align: "end",
114
+ anchor: /* @__PURE__ */ jsx(
115
+ "button",
116
+ {
117
+ ref: buttonRef,
118
+ type: "button",
119
+ className: JsonTree_module_default.actionButton,
120
+ "data-json-copy-button": true,
121
+ "data-state": state,
122
+ "aria-label": copyTitle,
123
+ title: labels.copyButtonTitle(copyTitle),
124
+ onClick: () => void onCopy(target, object ? "prettyJson" : "value"),
125
+ onContextMenu: (event) => {
126
+ event.preventDefault();
127
+ event.stopPropagation();
128
+ store.set({ id: id7, target, state, menuOpen: true });
129
+ },
130
+ children: state === "copied" ? /* @__PURE__ */ jsx(IconCheckOutlineRegular, { size: 12 }) : /* @__PURE__ */ jsx(IconCopyOutlineRegular, { size: 12 })
131
+ }
132
+ ),
133
+ items: object ? objectCopyMenuItems(labels) : valueCopyMenuItems(labels),
134
+ onSelect: (mode) => {
135
+ void onCopy(target, mode);
136
+ },
137
+ onClose,
138
+ getAnchorRect: () => buttonRef.current.getBoundingClientRect()
139
+ }
140
+ ) });
141
+ }
142
+ function isExpandableValue(value) {
143
+ return typeof value === "object" && value !== null && !(value instanceof Date);
144
+ }
145
+ function entriesOf(value) {
146
+ if (Array.isArray(value)) {
147
+ return value.map((item, index) => [String(index), item]);
148
+ }
149
+ return Object.keys(value).map((key) => [key, value[key]]);
150
+ }
151
+ function bracketOf(value) {
152
+ return Array.isArray(value) ? ["[", "]"] : ["{", "}"];
153
+ }
154
+ function previewPrimitive(value) {
155
+ if (value === null) return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.keywordValue, children: "null" });
156
+ if (typeof value === "string") {
157
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.stringValue, children: JSON.stringify(value) });
158
+ }
159
+ if (typeof value === "number") {
160
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.numberValue, children: String(value) });
161
+ }
162
+ if (typeof value === "boolean") {
163
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.keywordValue, children: String(value) });
164
+ }
165
+ if (typeof value === "bigint") {
166
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: value.toString() });
167
+ }
168
+ if (typeof value === "undefined") {
169
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: "undefined" });
170
+ }
171
+ if (typeof value === "symbol") {
172
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: value.description ?? "Symbol" });
173
+ }
174
+ if (typeof value === "function") {
175
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: value.name || "Function" });
176
+ }
177
+ return null;
178
+ }
179
+ function previewValue(value, depth) {
180
+ if (!isExpandableValue(value)) return previewPrimitive(value);
181
+ const array = Array.isArray(value);
182
+ const entries = entriesOf(value);
183
+ const limit = array ? ARRAY_PREVIEW_LIMIT : OBJECT_PREVIEW_LIMIT;
184
+ const visible = entries.slice(0, limit);
185
+ const [open, close] = bracketOf(value);
186
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
187
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: open }),
188
+ depth >= PREVIEW_DEPTH_LIMIT ? /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.previewEllipsis, children: "\u2026" }) : visible.map(([key, item], index) => /* @__PURE__ */ jsxs("span", { children: [
189
+ index > 0 && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: ", " }),
190
+ !array && /* @__PURE__ */ jsxs(Fragment, { children: [
191
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.previewProperty, children: key }),
192
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: ": " })
193
+ ] }),
194
+ previewValue(item, depth + 1)
195
+ ] }, key)),
196
+ depth < PREVIEW_DEPTH_LIMIT && entries.length > limit && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.previewEllipsis, children: ", \u2026" }),
197
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: close })
198
+ ] });
199
+ }
200
+ function primitiveValue(value) {
201
+ if (value === null) return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.keywordValue, children: "null" });
202
+ if (typeof value === "string") {
203
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.stringValue, children: JSON.stringify(value) });
204
+ }
205
+ if (typeof value === "boolean") {
206
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.keywordValue, children: String(value) });
207
+ }
208
+ if (typeof value === "number") {
209
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.numberValue, children: String(value) });
210
+ }
211
+ if (typeof value === "bigint") {
212
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.numberValue, children: `${value.toString()}n` });
213
+ }
214
+ if (value instanceof Date) {
215
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: value.toISOString() });
216
+ }
217
+ if (typeof value === "function") {
218
+ return /* @__PURE__ */ jsxs("span", { className: JsonTree_module_default.otherValue, children: [
219
+ "function() ",
220
+ "{ }"
221
+ ] });
222
+ }
223
+ if (typeof value === "undefined") {
224
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: "undefined" });
225
+ }
226
+ return /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.otherValue, children: value.toString() });
227
+ }
228
+ function fieldText(field) {
229
+ return field === "" ? '""' : field;
230
+ }
231
+ function pathId(path) {
232
+ return path.map((part) => typeof part === "number" ? `n${String(part)}` : `s${String(part.length)}:${part}`).join("/");
233
+ }
234
+ function claimFocus(button) {
235
+ button.focus();
236
+ }
237
+ function moveFocus(button, direction) {
238
+ const tree = button.closest('[role="tree"]');
239
+ if (tree === null) return;
240
+ const expanders = Array.from(tree.querySelectorAll("[data-json-expander]"));
241
+ const current = expanders.indexOf(button);
242
+ if (current < 0 || expanders.length === 0) return;
243
+ const next = (current + direction + expanders.length) % expanders.length;
244
+ const nextExpander = expanders[next];
245
+ if (nextExpander !== void 0) claimFocus(nextExpander);
246
+ }
247
+ function NodeField({
248
+ field,
249
+ expandable,
250
+ onToggle
251
+ }) {
252
+ if (field === void 0) return null;
253
+ return /* @__PURE__ */ jsxs("span", { className: clsx(JsonTree_module_default.label, expandable && JsonTree_module_default.clickableLabel), onClick: expandable ? onToggle : void 0, children: [
254
+ fieldText(field),
255
+ ":"
256
+ ] });
257
+ }
258
+ function JsonString({
259
+ collapsedStringLines,
260
+ stringWrapping,
261
+ field,
262
+ labels,
263
+ lastElement,
264
+ renderCopy,
265
+ value
266
+ }) {
267
+ const contentsId = useId();
268
+ const contentRef = useRef(null);
269
+ const rawRef = useRef(null);
270
+ const [expanded, setExpanded] = useState(false);
271
+ const [wrapped, setWrapped] = useState(false);
272
+ const [truncated, setTruncated] = useState(false);
273
+ useLayoutEffect(() => {
274
+ if (expanded) return;
275
+ const content = contentRef.current;
276
+ const measure = () => {
277
+ const lineHeight = Number.parseFloat(getComputedStyle(content).lineHeight);
278
+ setTruncated(content.scrollHeight > lineHeight * collapsedStringLines);
279
+ };
280
+ measure();
281
+ if (typeof ResizeObserver === "undefined") return;
282
+ const observer = new ResizeObserver(measure);
283
+ observer.observe(content);
284
+ return () => {
285
+ observer.disconnect();
286
+ };
287
+ }, [collapsedStringLines, expanded, field, lastElement, value]);
288
+ useLayoutEffect(() => {
289
+ if (!expanded) return;
290
+ const raw = rawRef.current;
291
+ const clips = [];
292
+ const tree = raw.closest(`.${JsonTree_module_default.root}`);
293
+ for (let parent = tree.parentElement; parent !== null; parent = parent.parentElement) {
294
+ if (/auto|scroll|hidden|clip/.test(getComputedStyle(parent).overflowY)) clips.push(parent);
295
+ }
296
+ const measure = () => {
297
+ let top = 0;
298
+ let bottom = window.innerHeight;
299
+ for (const clip of clips) {
300
+ const rect = clip.getBoundingClientRect();
301
+ const style = getComputedStyle(clip);
302
+ top = Math.max(top, rect.top + clip.clientTop);
303
+ bottom = Math.min(
304
+ bottom,
305
+ rect.top + clip.clientTop + clip.clientHeight - Number.parseFloat(style.paddingBottom)
306
+ );
307
+ }
308
+ const available = bottom - Math.max(top, raw.getBoundingClientRect().top);
309
+ raw.style.maxHeight = `${Math.max(16, available - 4)}px`;
310
+ };
311
+ measure();
312
+ const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(measure);
313
+ observer?.observe(raw);
314
+ for (const clip of clips) observer?.observe(clip);
315
+ window.addEventListener("resize", measure);
316
+ window.addEventListener("scroll", measure, true);
317
+ return () => {
318
+ observer?.disconnect();
319
+ window.removeEventListener("resize", measure);
320
+ window.removeEventListener("scroll", measure, true);
321
+ };
322
+ }, [expanded, value]);
323
+ if (expanded) {
324
+ const fieldId = `${contentsId}-field`;
325
+ return /* @__PURE__ */ jsxs("div", { className: JsonTree_module_default.stringField, "data-expanded": true, children: [
326
+ field !== void 0 && /* @__PURE__ */ jsxs("span", { id: fieldId, className: JsonTree_module_default.label, children: [
327
+ fieldText(field),
328
+ ":"
329
+ ] }),
330
+ /* @__PURE__ */ jsx(
331
+ "pre",
332
+ {
333
+ ref: rawRef,
334
+ id: contentsId,
335
+ className: JsonTree_module_default.stringRaw,
336
+ "data-wrap": wrapped,
337
+ tabIndex: 0,
338
+ "aria-labelledby": field === void 0 ? void 0 : fieldId,
339
+ children: value
340
+ }
341
+ ),
342
+ !lastElement && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: "," }),
343
+ /* @__PURE__ */ jsxs("div", { className: JsonTree_module_default.stringActions, children: [
344
+ stringWrapping !== void 0 && /* @__PURE__ */ jsx(
345
+ "button",
346
+ {
347
+ type: "button",
348
+ className: JsonTree_module_default.actionButton,
349
+ "aria-label": stringWrapping.label,
350
+ title: stringWrapping.label,
351
+ "aria-pressed": wrapped,
352
+ "aria-controls": contentsId,
353
+ onClick: () => {
354
+ const next = !wrapped;
355
+ setWrapped(next);
356
+ stringWrapping.setDefault(next);
357
+ },
358
+ children: /* @__PURE__ */ jsx(IconWrapLinesOutlineRegular, { size: 12 })
359
+ }
360
+ ),
361
+ /* @__PURE__ */ jsx(
362
+ "button",
363
+ {
364
+ type: "button",
365
+ className: JsonTree_module_default.actionButton,
366
+ "aria-label": labels.collapseNode,
367
+ title: labels.collapseNode,
368
+ "aria-expanded": true,
369
+ "aria-controls": contentsId,
370
+ onClick: () => {
371
+ setExpanded(false);
372
+ },
373
+ children: /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M9.5 1.5V6.5H14.5M1.5 9.5H6.5V14.5" }) })
374
+ }
375
+ ),
376
+ renderCopy?.(true)
377
+ ] })
378
+ ] });
379
+ }
380
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
381
+ renderCopy?.(),
382
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.stringField, "data-expanded": expanded, children: /* @__PURE__ */ jsxs("span", { ref: contentRef, id: contentsId, className: JsonTree_module_default.stringText, children: [
383
+ truncated && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.stringToggleSlot, children: /* @__PURE__ */ jsxs(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ className: JsonTree_module_default.stringToggle,
388
+ "aria-label": labels.expandNode,
389
+ "aria-expanded": false,
390
+ "aria-controls": contentsId,
391
+ onClick: () => {
392
+ setWrapped(stringWrapping?.getDefault() ?? false);
393
+ setExpanded(true);
394
+ },
395
+ children: [
396
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2026" }),
397
+ labels.expandNode
398
+ ]
399
+ }
400
+ ) }),
401
+ field !== void 0 && /* @__PURE__ */ jsxs("span", { className: JsonTree_module_default.label, children: [
402
+ fieldText(field),
403
+ ":"
404
+ ] }),
405
+ primitiveValue(value),
406
+ !lastElement && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: "," })
407
+ ] }) })
408
+ ] });
409
+ }
410
+ function JsonTreeNode({
411
+ collapsedStringLines,
412
+ stringWrapping,
413
+ field,
414
+ initialExpanded,
415
+ labels,
416
+ lastElement,
417
+ onClaimTabStop,
418
+ onRowHover,
419
+ path,
420
+ renderCopy,
421
+ tabStopId,
422
+ value
423
+ }) {
424
+ const contentsId = useId();
425
+ const expanderRef = useRef(null);
426
+ const [expanded, setExpanded] = useState(initialExpanded);
427
+ const nodeId = pathId(path);
428
+ const container = isExpandableValue(value);
429
+ const entries = container ? entriesOf(value) : [];
430
+ const expandable = entries.length > 0;
431
+ const toggle = () => {
432
+ setExpanded((current) => !current);
433
+ claimFocus(expanderRef.current);
434
+ };
435
+ const onExpanderKeyDown = (event) => {
436
+ if (event.key === "ArrowRight" || event.key === "ArrowLeft") {
437
+ event.preventDefault();
438
+ setExpanded(event.key === "ArrowRight");
439
+ return;
440
+ }
441
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
442
+ event.preventDefault();
443
+ moveFocus(event.currentTarget, event.key === "ArrowUp" ? -1 : 1);
444
+ }
445
+ };
446
+ const row = (children, ariaExpanded) => /* @__PURE__ */ jsxs(
447
+ "div",
448
+ {
449
+ className: JsonTree_module_default.row,
450
+ role: "treeitem",
451
+ "aria-expanded": ariaExpanded,
452
+ onMouseOver: (event) => {
453
+ event.stopPropagation();
454
+ onRowHover(event.currentTarget, { path, value });
455
+ },
456
+ children: [
457
+ typeof value !== "string" && renderCopy?.({ path, value }),
458
+ children
459
+ ]
460
+ }
461
+ );
462
+ if (typeof value === "string") {
463
+ return row(
464
+ /* @__PURE__ */ jsx(
465
+ JsonString,
466
+ {
467
+ collapsedStringLines,
468
+ stringWrapping,
469
+ field,
470
+ value,
471
+ labels,
472
+ lastElement,
473
+ renderCopy: renderCopy === void 0 ? void 0 : (persistent) => renderCopy({ path, value }, persistent)
474
+ }
475
+ )
476
+ );
477
+ }
478
+ if (!container) {
479
+ return row(
480
+ /* @__PURE__ */ jsxs(Fragment, { children: [
481
+ /* @__PURE__ */ jsx(NodeField, { field, expandable: false, onToggle: toggle }),
482
+ primitiveValue(value),
483
+ !lastElement && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: "," })
484
+ ] })
485
+ );
486
+ }
487
+ const [open, close] = bracketOf(value);
488
+ if (!expandable) {
489
+ return row(
490
+ /* @__PURE__ */ jsxs(Fragment, { children: [
491
+ /* @__PURE__ */ jsx(NodeField, { field, expandable: false, onToggle: toggle }),
492
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: open }),
493
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: close }),
494
+ !lastElement && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: "," })
495
+ ] })
496
+ );
497
+ }
498
+ return row(
499
+ /* @__PURE__ */ jsxs(Fragment, { children: [
500
+ /* @__PURE__ */ jsx(
501
+ "span",
502
+ {
503
+ ref: expanderRef,
504
+ className: clsx(JsonTree_module_default.expander, expanded ? JsonTree_module_default.collapseIcon : JsonTree_module_default.expandIcon),
505
+ "data-json-expander": true,
506
+ role: "button",
507
+ "aria-label": expanded ? labels.collapseNode : labels.expandNode,
508
+ "aria-expanded": expanded,
509
+ "aria-controls": expanded ? contentsId : void 0,
510
+ tabIndex: tabStopId === nodeId ? 0 : -1,
511
+ onFocus: () => {
512
+ onClaimTabStop(nodeId);
513
+ },
514
+ onClick: toggle,
515
+ onKeyDown: onExpanderKeyDown
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsxs("span", { className: JsonTree_module_default.summary, children: [
519
+ /* @__PURE__ */ jsx(NodeField, { field, expandable: true, onToggle: toggle }),
520
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.preview, children: previewValue(value, 0) }),
521
+ !lastElement && /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: "," })
522
+ ] }),
523
+ expanded && /* @__PURE__ */ jsx("ul", { id: contentsId, role: "group", className: JsonTree_module_default.children, children: entries.map(([key, item], index) => /* @__PURE__ */ jsx(
524
+ JsonTreeNode,
525
+ {
526
+ collapsedStringLines,
527
+ stringWrapping,
528
+ field: key,
529
+ value: item,
530
+ path: [...path, Array.isArray(value) ? index : key],
531
+ labels,
532
+ lastElement: index === entries.length - 1,
533
+ initialExpanded: false,
534
+ tabStopId,
535
+ onClaimTabStop,
536
+ onRowHover,
537
+ renderCopy
538
+ },
539
+ key
540
+ )) })
541
+ ] }),
542
+ expanded
543
+ );
544
+ }
545
+ function formattedPath(path) {
546
+ return path.reduce((result, part) => {
547
+ if (typeof part === "number") return `${result}[${String(part)}]`;
548
+ return /^[A-Za-z_$][\w$]*$/.test(part) ? `${result}.${part}` : `${result}[${JSON.stringify(part)}]`;
549
+ }, "$");
550
+ }
551
+ function copyText(target, mode) {
552
+ if (mode === "path") return formattedPath(target.path);
553
+ if (mode === "prettyJson") return JSON.stringify(target.value, null, 2);
554
+ if (mode === "json") return JSON.stringify(target.value);
555
+ if (typeof target.value === "string") return target.value;
556
+ if (typeof target.value === "undefined") return "undefined";
557
+ if (typeof target.value === "bigint") return target.value.toString();
558
+ if (typeof target.value === "symbol") return target.value.description ?? "Symbol";
559
+ if (typeof target.value === "function") return target.value.name || "Function";
560
+ return JSON.stringify(target.value);
561
+ }
562
+ function JsonTree({
563
+ data,
564
+ label,
565
+ className,
566
+ collapsedStringLines = 3,
567
+ stringWrapping,
568
+ copyable = true,
569
+ expandTopLevel = true,
570
+ labels
571
+ }) {
572
+ const rootEntries = entriesOf(data);
573
+ const firstExpandableIndex = rootEntries.findIndex(
574
+ ([, value]) => isExpandableValue(value) && entriesOf(value).length > 0
575
+ );
576
+ const firstExpandableEntry = rootEntries[firstExpandableIndex];
577
+ const initialTabStopId = expandTopLevel ? firstExpandableEntry === void 0 ? null : pathId([Array.isArray(data) ? firstExpandableIndex : firstExpandableEntry[0]]) : isExpandableValue(data) && rootEntries.length > 0 ? pathId([]) : null;
578
+ const activeRowRef = useRef(void 0);
579
+ const resetTimer = useRef(void 0);
580
+ const copySequence = useRef(0);
581
+ const [copyStore] = useState(createCopyStore);
582
+ const [tabStopId, setTabStopId] = useState(initialTabStopId);
583
+ const setActiveRow = (row) => {
584
+ activeRowRef.current?.removeAttribute("data-json-copy-active");
585
+ activeRowRef.current = row;
586
+ row?.setAttribute("data-json-copy-active", "");
587
+ };
588
+ const clearCopyTarget = () => {
589
+ copySequence.current += 1;
590
+ if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
591
+ setActiveRow(void 0);
592
+ copyStore.set(void 0);
593
+ };
594
+ useEffect(
595
+ () => () => {
596
+ copySequence.current += 1;
597
+ if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
598
+ activeRowRef.current?.removeAttribute("data-json-copy-active");
599
+ },
600
+ []
601
+ );
602
+ useEffect(() => {
603
+ clearCopyTarget();
604
+ setTabStopId(initialTabStopId);
605
+ }, [data, expandTopLevel, initialTabStopId]);
606
+ const handleRowHover = (row, target) => {
607
+ if (!copyable || copyStore.get()?.menuOpen) return;
608
+ if (activeRowRef.current === row) return;
609
+ setActiveRow(row);
610
+ copyStore.set({ id: pathId(target.path), target, state: "idle", menuOpen: false });
611
+ };
612
+ const handleRootMouseOver = (event) => {
613
+ if (!copyable || copyStore.get()?.menuOpen) return;
614
+ if (!(event.target instanceof Element)) return;
615
+ if (event.target.closest("[data-json-copy-button]") === null) clearCopyTarget();
616
+ };
617
+ const copy = async (target, mode) => {
618
+ const sequence = ++copySequence.current;
619
+ const snapshot = {
620
+ id: pathId(target.path),
621
+ target,
622
+ state: "idle",
623
+ menuOpen: false
624
+ };
625
+ copyStore.set(snapshot);
626
+ let state;
627
+ try {
628
+ await navigator.clipboard.writeText(copyText(target, mode));
629
+ state = "copied";
630
+ } catch {
631
+ state = "failed";
632
+ }
633
+ const current = copyStore.get();
634
+ if (sequence !== copySequence.current || current?.target !== target) return;
635
+ copyStore.set({ ...current, state });
636
+ if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
637
+ resetTimer.current = setTimeout(() => {
638
+ const current2 = copyStore.get();
639
+ if (current2?.target === target) copyStore.set({ ...current2, state: "idle" });
640
+ }, 1500);
641
+ };
642
+ const [rootOpen, rootClose] = bracketOf(data);
643
+ const renderCopy = copyable ? (target, persistent = false) => /* @__PURE__ */ jsx(
644
+ JsonCopyAction,
645
+ {
646
+ store: copyStore,
647
+ target,
648
+ persistent,
649
+ labels,
650
+ onCopy: copy,
651
+ onClose: clearCopyTarget
652
+ }
653
+ ) : void 0;
654
+ return /* @__PURE__ */ jsx(
655
+ "div",
656
+ {
657
+ className: clsx(JsonTree_module_default.root, className),
658
+ style: { "--json-tree-collapsed-lines": collapsedStringLines },
659
+ onMouseOver: handleRootMouseOver,
660
+ onMouseLeave: () => {
661
+ if (!copyStore.get()?.menuOpen) clearCopyTarget();
662
+ },
663
+ children: expandTopLevel ? /* @__PURE__ */ jsxs("div", { className: JsonTree_module_default.expandedTopLevel, children: [
664
+ /* @__PURE__ */ jsxs(
665
+ "div",
666
+ {
667
+ className: clsx(JsonTree_module_default.row, JsonTree_module_default.topLevelBracket),
668
+ "data-json-root-row": true,
669
+ onMouseOver: (event) => {
670
+ event.stopPropagation();
671
+ handleRowHover(event.currentTarget, { path: [], value: data });
672
+ },
673
+ children: [
674
+ renderCopy?.({ path: [], value: data }),
675
+ /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: rootOpen })
676
+ ]
677
+ }
678
+ ),
679
+ /* @__PURE__ */ jsx("div", { "aria-label": label, className: clsx(JsonTree_module_default.container, JsonTree_module_default.expandedTopLevelContainer), role: "tree", children: rootEntries.map(([key, value], index) => /* @__PURE__ */ jsx(
680
+ JsonTreeNode,
681
+ {
682
+ collapsedStringLines,
683
+ stringWrapping,
684
+ field: key,
685
+ value,
686
+ path: [Array.isArray(data) ? index : key],
687
+ labels,
688
+ lastElement: index === rootEntries.length - 1,
689
+ initialExpanded: false,
690
+ tabStopId,
691
+ onClaimTabStop: setTabStopId,
692
+ onRowHover: handleRowHover,
693
+ renderCopy
694
+ },
695
+ key
696
+ )) }),
697
+ /* @__PURE__ */ jsx("div", { className: clsx(JsonTree_module_default.row, JsonTree_module_default.topLevelBracket), children: /* @__PURE__ */ jsx("span", { className: JsonTree_module_default.punctuation, children: rootClose }) })
698
+ ] }) : /* @__PURE__ */ jsx("div", { "aria-label": label, className: JsonTree_module_default.container, role: "tree", children: /* @__PURE__ */ jsx(
699
+ JsonTreeNode,
700
+ {
701
+ collapsedStringLines,
702
+ stringWrapping,
703
+ value: data,
704
+ path: [],
705
+ labels,
706
+ lastElement: true,
707
+ initialExpanded: true,
708
+ tabStopId,
709
+ onClaimTabStop: setTabStopId,
710
+ onRowHover: handleRowHover,
711
+ renderCopy
712
+ }
713
+ ) })
714
+ }
715
+ );
716
+ }
717
+
718
+ // src/TerminalBlock.tsx
719
+ import { useCallback as useCallback3, useMemo, useState as useState3 } from "react";
720
+ import clsx2 from "clsx";
721
+
722
+ // src/ansi.ts
723
+ import Anser from "anser";
724
+ var TOKEN_BY_BASIC_RGB = {
725
+ "0,0,0": "var(--dsw-alias-label-primary)",
726
+ "255,255,255": "var(--dsw-alias-label-primary)",
727
+ "85,85,85": "var(--dsw-alias-label-tertiary)",
728
+ "187,0,0": "var(--dsw-alias-state-error-primary)",
729
+ "255,85,85": "var(--dsw-alias-state-error-secondary)",
730
+ "0,187,0": "var(--dsw-alias-state-success-primary)",
731
+ "0,255,0": "var(--dsw-alias-state-success-secondary)",
732
+ "187,187,0": "var(--dsw-alias-state-warn-primary)",
733
+ "255,255,85": "var(--dsw-alias-state-warn-secondary)",
734
+ "0,0,187": "var(--dsw-alias-state-business-primary)",
735
+ "85,85,255": "var(--dsw-static-blue-400)",
736
+ "0,187,187": "var(--dsw-static-blue-600)",
737
+ "85,255,255": "var(--dsw-static-blue-500)"
738
+ };
739
+ var STYLE_BY_DECORATION = {
740
+ bold: { fontWeight: 700 },
741
+ dim: { opacity: 0.7 },
742
+ italic: { fontStyle: "italic" },
743
+ underline: { textDecoration: "underline" },
744
+ strikethrough: { textDecoration: "line-through" },
745
+ hidden: { visibility: "hidden" }
746
+ };
747
+ var OSC_SEQUENCE = /\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)?/g;
748
+ var NON_CSI_ESCAPE = /\u001b(?!\[)[\u0020-\u002f]*[\u0030-\u007e]?/g;
749
+ var INERT_CONTROL = /[\u0000-\u0007\u000b-\u001a\u001c-\u001f\u007f]/g;
750
+ var NEEDS_REPLAY = /\r|\u0008|\u001b\[[\u0030-\u003f]*[\u0020-\u002f]*K/;
751
+ var SGR_SEQUENCE = /\u001b\[([\u0030-\u003f]*)[\u0020-\u002f]*m/g;
752
+ var TAB_WIDTH = 8;
753
+ var ZERO_WIDTH = /^[\p{Mn}\p{Me}\p{Cf}\u200b-\u200f\u2060]$/u;
754
+ var WIDE_CHAR = new RegExp(
755
+ "\\p{Script=Han}|\\p{Script=Hiragana}|\\p{Script=Katakana}|\\p{Script=Hangul}|\\p{Emoji_Presentation}|[\\uff01-\\uff60\\u3000-\\u303e]",
756
+ "u"
757
+ );
758
+ function isWide(char) {
759
+ const code = char.codePointAt(0);
760
+ if (code === void 0 || code < 4352) return false;
761
+ return WIDE_CHAR.test(char);
762
+ }
763
+ var SGR_NONE = { fg: "", bg: "", attrs: [] };
764
+ var ATTR_CLOSERS = {
765
+ 22: ["1", "2"],
766
+ 23: ["3"],
767
+ 24: ["4"],
768
+ 25: ["5", "6"],
769
+ 27: ["7"],
770
+ 28: ["8"],
771
+ 29: ["9"]
772
+ };
773
+ function foldSgr(state, params) {
774
+ const codes = params === "" ? ["0"] : params.split(";");
775
+ let next = state;
776
+ for (let index = 0; index < codes.length; index++) {
777
+ const code = String(codes[index]);
778
+ if (code === "" || code === "0") {
779
+ next = SGR_NONE;
780
+ continue;
781
+ }
782
+ if (code === "38" || code === "48") {
783
+ const kind = codes[index + 1] ?? "";
784
+ const span = kind === "2" ? 4 : kind === "5" ? 2 : 0;
785
+ const value = codes.slice(index, index + span + 1).join(";");
786
+ next = code === "38" ? { ...next, fg: value } : { ...next, bg: value };
787
+ index += span;
788
+ continue;
789
+ }
790
+ const closes = ATTR_CLOSERS[code];
791
+ if (closes !== void 0) {
792
+ next = { ...next, attrs: next.attrs.filter((attr) => !closes.includes(attr)) };
793
+ continue;
794
+ }
795
+ const numeric = Number(code);
796
+ if (code === "39") {
797
+ next = { ...next, fg: "" };
798
+ continue;
799
+ }
800
+ if (code === "49") {
801
+ next = { ...next, bg: "" };
802
+ continue;
803
+ }
804
+ if (numeric >= 30 && numeric <= 37 || numeric >= 90 && numeric <= 97) {
805
+ next = { ...next, fg: code };
806
+ continue;
807
+ }
808
+ if (numeric >= 40 && numeric <= 47 || numeric >= 100 && numeric <= 107) {
809
+ next = { ...next, bg: code };
810
+ continue;
811
+ }
812
+ if (!next.attrs.includes(code)) next = { ...next, attrs: [...next.attrs, code] };
813
+ }
814
+ return next;
815
+ }
816
+ function openSgr(state) {
817
+ const codes = [...state.attrs];
818
+ if (state.fg !== "") codes.push(state.fg);
819
+ if (state.bg !== "") codes.push(state.bg);
820
+ return codes.length === 0 ? "" : `\x1B[${codes.join(";")}m`;
821
+ }
822
+ function sameSgr(a, b) {
823
+ return a.fg === b.fg && a.bg === b.bg && a.attrs.length === b.attrs.length && a.attrs.every((attr, index) => attr === b.attrs[index]);
824
+ }
825
+ function replayLine(line, entrySgr) {
826
+ const csi = /\u001b\[([\u0030-\u003f]*)[\u0020-\u002f]*([\u0040-\u007e])/g;
827
+ const columns = [];
828
+ let cursor = 0;
829
+ let sgr = entrySgr;
830
+ let at = 0;
831
+ const clear = (index, fill) => {
832
+ const cell = columns[index];
833
+ if (cell?.spacer === true && index > 0) columns[index - 1] = { sgr, char: fill };
834
+ else if (cell !== void 0 && isWide(cell.char) && columns[index + 1]?.spacer === true) {
835
+ columns[index + 1] = { sgr, char: fill };
836
+ }
837
+ columns[index] = { sgr, char: fill };
838
+ };
839
+ const consume = (chunk) => {
840
+ for (const char of chunk) {
841
+ if (char === "\r") {
842
+ cursor = 0;
843
+ continue;
844
+ }
845
+ if (char === "\b") {
846
+ cursor = Math.max(0, cursor - 1);
847
+ continue;
848
+ }
849
+ if (char === " ") {
850
+ const stop = cursor + TAB_WIDTH - cursor % TAB_WIDTH;
851
+ for (; cursor < stop; cursor++) columns[cursor] ?? (columns[cursor] = { sgr, char: " " });
852
+ continue;
853
+ }
854
+ if (ZERO_WIDTH.test(char)) {
855
+ const base = cursor > 0 ? columns[cursor - 1] : void 0;
856
+ if (base !== void 0) columns[cursor - 1] = { sgr: base.sgr, char: base.char + char };
857
+ continue;
858
+ }
859
+ clear(cursor, " ");
860
+ columns[cursor] = { sgr, char };
861
+ cursor++;
862
+ if (isWide(char)) {
863
+ columns[cursor] = { sgr, char: "", spacer: true };
864
+ cursor++;
865
+ }
866
+ }
867
+ };
868
+ for (const match of line.matchAll(csi)) {
869
+ consume(line.slice(at, match.index));
870
+ at = match.index + match[0].length;
871
+ const params = String(match[1]);
872
+ const final = String(match[2]);
873
+ if (final === "K") {
874
+ const mode = String(params.split(";")[0]);
875
+ if (mode === "1") for (let index = 0; index <= cursor; index++) clear(index, " ");
876
+ else columns.length = mode === "2" ? 0 : cursor;
877
+ continue;
878
+ }
879
+ if (final !== "m") continue;
880
+ sgr = foldSgr(sgr, params);
881
+ }
882
+ consume(line.slice(at));
883
+ let out = "";
884
+ let active = entrySgr;
885
+ for (let index = 0; index < columns.length; index++) {
886
+ const column = columns[index] ?? { sgr: SGR_NONE, char: " " };
887
+ if (!sameSgr(column.sgr, active)) {
888
+ if (!sameSgr(active, SGR_NONE)) out += "\x1B[0m";
889
+ out += openSgr(column.sgr);
890
+ active = column.sgr;
891
+ }
892
+ const leadIntact = index > 0 && isWide(columns[index - 1]?.char ?? "");
893
+ out += column.spacer === true && !leadIntact ? " " : column.char;
894
+ }
895
+ if (!sameSgr(active, sgr)) {
896
+ if (!sameSgr(active, SGR_NONE)) out += "\x1B[0m";
897
+ out += openSgr(sgr);
898
+ }
899
+ return { text: out, sgr };
900
+ }
901
+ function applyCursorMovements(text) {
902
+ const replayed = [];
903
+ let sgr = SGR_NONE;
904
+ for (const raw of text.split("\n")) {
905
+ const line = raw.replace(/\r+$/, "");
906
+ if (NEEDS_REPLAY.test(line)) {
907
+ const result = replayLine(line, sgr);
908
+ replayed.push(result.text);
909
+ sgr = result.sgr;
910
+ continue;
911
+ }
912
+ replayed.push(line);
913
+ for (const match of line.matchAll(SGR_SEQUENCE)) sgr = foldSgr(sgr, String(match[1]));
914
+ }
915
+ return replayed.join("\n");
916
+ }
917
+ function sanitize(text) {
918
+ const escaped = text.replace(OSC_SEQUENCE, "").replace(NON_CSI_ESCAPE, "");
919
+ return applyCursorMovements(escaped).replace(INERT_CONTROL, "");
920
+ }
921
+ function resolveStyle(chunk) {
922
+ const style = {};
923
+ const background = chunk.bg === null ? void 0 : `rgb(${chunk.bg})`;
924
+ if (background !== void 0) style.backgroundColor = background;
925
+ if (chunk.fg !== null) {
926
+ const literal = `rgb(${chunk.fg})`;
927
+ style.color = background === void 0 ? TOKEN_BY_BASIC_RGB[chunk.fg.replace(/\s+/g, "")] ?? literal : literal;
928
+ }
929
+ for (const decoration of chunk.decorations) Object.assign(style, STYLE_BY_DECORATION[decoration]);
930
+ return Object.keys(style).length === 0 ? void 0 : style;
931
+ }
932
+ function parseAnsiLines(text) {
933
+ let current = [];
934
+ const lines = [current];
935
+ for (const chunk of Anser.ansiToJson(sanitize(text), { json: true, remove_empty: true })) {
936
+ const style = resolveStyle(chunk);
937
+ for (const [index, part] of chunk.content.split("\n").entries()) {
938
+ if (index > 0) {
939
+ current = [];
940
+ lines.push(current);
941
+ }
942
+ if (part !== "") current.push({ text: part, style });
943
+ }
944
+ }
945
+ return lines;
946
+ }
947
+
948
+ // src/head-tail-cap.ts
949
+ function headTailCap(total, maxLines, expanded) {
950
+ const hidden = total - maxLines;
951
+ const headLines = Math.ceil(maxLines / 2);
952
+ return { hidden, capped: hidden > 0 && !expanded, headLines, tailLines: maxLines - headLines };
953
+ }
954
+
955
+ // src/use-copy-feedback.ts
956
+ import { useCallback as useCallback2, useState as useState2 } from "react";
957
+ var COPIED_FEEDBACK_MS = 1e3;
958
+ function useCopyFeedback(text) {
959
+ const [copied, setCopied] = useState2(false);
960
+ const onCopy = useCallback2(() => {
961
+ if (copied) return;
962
+ void writeClipboard(text).then((ok) => {
963
+ if (!ok) return;
964
+ setCopied(true);
965
+ window.setTimeout(() => {
966
+ setCopied(false);
967
+ }, COPIED_FEEDBACK_MS);
968
+ });
969
+ }, [copied, text]);
970
+ return { copied, onCopy };
971
+ }
972
+
973
+ // .build/css/TerminalBlock.module.mjs
974
+ var id2 = "@seekbuddy/dsh-ui/TerminalBlock.module.css";
975
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id2 + '"]')) {
976
+ const element = document.createElement("style");
977
+ element.setAttribute("data-dsh-ui-primitives", id2);
978
+ element.textContent = ".OBf4Nq_block{--dsl-terminal-radius:var(--dsw-radius-lg);--dsl-terminal-line-height:22px;--dsl-terminal-font:var(--dsw-font-markdown-code-block);--dsl-terminal-gutter:30px;padding-left:var(--dsl-terminal-gutter);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border-radius:var(--dsl-terminal-radius);margin:16px 0;position:relative;overflow:hidden}.OBf4Nq_header{margin-left:calc(-1 * var(--dsl-terminal-gutter));padding:9px 14px 9px var(--dsl-terminal-gutter);border-top-left-radius:var(--dsl-terminal-radius);border-top-right-radius:var(--dsl-terminal-radius);align-items:flex-start;gap:12px;max-height:150px;display:flex;overflow-y:auto}.OBf4Nq_header::-webkit-scrollbar-thumb{border-radius:var(--dsw-radius-sm);background-clip:padding-box;border:2px solid #0000}.OBf4Nq_header::-webkit-scrollbar-track{margin:6px}.OBf4Nq_block[data-body] .OBf4Nq_header{border-bottom:.5px solid var(--dsw-alias-border-l2)}.OBf4Nq_prompt{min-width:0;font:var(--dsl-terminal-font);flex-direction:column;flex:1;display:flex}.OBf4Nq_promptLine{min-width:0;line-height:var(--dsl-terminal-line-height);align-items:baseline;gap:8px;display:flex;position:relative}.OBf4Nq_runState{left:calc(-1 * var(--dsl-terminal-gutter) + 8px);position:absolute;top:50%;transform:translateY(-50%)}.OBf4Nq_runStateLabel{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.OBf4Nq_cwd{color:var(--dsw-alias-label-tertiary);flex:none}.OBf4Nq_command{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:var(--dsl-terminal-command-whitespace,pre);overflow-wrap:anywhere;overflow:hidden}.OBf4Nq_status{height:var(--dsl-terminal-line-height);color:var(--dsw-alias-state-error-primary);flex:none;position:sticky;top:0}.OBf4Nq_copyButton{background-color:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-secondary);cursor:pointer;font:var(--dsw-font-xs-13);line-height:var(--dsl-terminal-line-height);border:none;flex:none;margin:0;padding:0;position:sticky;top:0}.OBf4Nq_output{max-height:var(--dsl-terminal-output-max-height,none);font:var(--dsl-terminal-font);padding:12px 14px 12px 0;overflow:auto}.OBf4Nq_output::-webkit-scrollbar-thumb{border-radius:var(--dsw-radius-sm);background-clip:padding-box;border:2px solid #0000}.OBf4Nq_output::-webkit-scrollbar-track{margin:6px}.OBf4Nq_line{min-height:var(--dsl-terminal-line-height);white-space:var(--dsl-terminal-line-whitespace,pre);overflow-wrap:anywhere}.OBf4Nq_expand{width:100%;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;text-align:left;background-color:#0000;border:none;padding:0;display:block}.OBf4Nq_expand:hover{color:var(--dsw-alias-label-secondary)}.OBf4Nq_empty{font:var(--dsl-terminal-font);color:var(--dsw-alias-label-tertiary);padding:12px 14px 12px 0}";
979
+ document.head.appendChild(element);
980
+ }
981
+ var TerminalBlock_module_default = { "cwd": "OBf4Nq_cwd", "header": "OBf4Nq_header", "command": "OBf4Nq_command", "runStateLabel": "OBf4Nq_runStateLabel", "expand": "OBf4Nq_expand", "prompt": "OBf4Nq_prompt", "promptLine": "OBf4Nq_promptLine", "block": "OBf4Nq_block", "status": "OBf4Nq_status", "copyButton": "OBf4Nq_copyButton", "empty": "OBf4Nq_empty", "runState": "OBf4Nq_runState", "output": "OBf4Nq_output", "line": "OBf4Nq_line" };
982
+
983
+ // src/TerminalBlock.tsx
984
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
985
+ var DEFAULT_TERMINAL_MAX_LINES = 16;
986
+ function promptLabel(cwd, home) {
987
+ const trimmed = cwd.replace(/[/\\]+$/, "");
988
+ if (home !== void 0 && trimmed === home.replace(/[/\\]+$/, "")) return "~";
989
+ const segment = trimmed.split(/[/\\]/).pop();
990
+ return segment === void 0 || segment === "" ? cwd : segment;
991
+ }
992
+ function statusText(exitCode, signal, labels) {
993
+ if (signal !== void 0) return labels.signal(signal);
994
+ if (exitCode === null) return labels.noExitCode;
995
+ if (exitCode !== void 0 && exitCode !== 0) return labels.exitCode(exitCode);
996
+ return void 0;
997
+ }
998
+ function runState(running, exitCode, signal, labels) {
999
+ if (running) return { state: "ongoing", label: labels.running };
1000
+ if (statusText(exitCode, signal, labels) !== void 0) return { state: "error", label: labels.failed };
1001
+ return { state: "done", label: labels.done };
1002
+ }
1003
+ function renderLine(line) {
1004
+ return line.map(
1005
+ (span, index) => span.style === void 0 ? span.text : /* @__PURE__ */ jsx2("span", { style: span.style, children: span.text }, index)
1006
+ );
1007
+ }
1008
+ function TerminalBlock({
1009
+ command,
1010
+ cwd,
1011
+ home,
1012
+ output,
1013
+ exitCode,
1014
+ signal,
1015
+ running = false,
1016
+ maxLines = DEFAULT_TERMINAL_MAX_LINES,
1017
+ copyText: copyText4,
1018
+ runStateDot = true,
1019
+ className,
1020
+ labels
1021
+ }) {
1022
+ const copy = labels;
1023
+ const text = output ?? "";
1024
+ const lines = useMemo(() => {
1025
+ const parsed = parseAnsiLines(text);
1026
+ const last = parsed[parsed.length - 1];
1027
+ const terminated = parsed.length > 1 && last !== void 0 && last.every((span) => span.text === "");
1028
+ return terminated ? parsed.slice(0, -1) : parsed;
1029
+ }, [text]);
1030
+ const [expanded, setExpanded] = useState3(false);
1031
+ const { copied, onCopy } = useCopyFeedback(copyText4 ?? text);
1032
+ const onToggle = useCallback3(() => {
1033
+ setExpanded((value) => !value);
1034
+ }, []);
1035
+ const status = statusText(exitCode, signal, copy);
1036
+ const state = runState(running, exitCode, signal, copy);
1037
+ const commandLines = useMemo(() => {
1038
+ const body2 = command.endsWith("\n") ? command.slice(0, -1) : command;
1039
+ return body2.split("\n");
1040
+ }, [command]);
1041
+ const empty = lines.every((line) => line.every((span) => span.text.trim() === ""));
1042
+ const { hidden, capped, headLines, tailLines } = headTailCap(lines.length, maxLines, expanded);
1043
+ const body = !running || !empty;
1044
+ return /* @__PURE__ */ jsxs2(
1045
+ "div",
1046
+ {
1047
+ className: clsx2(TerminalBlock_module_default.block, className),
1048
+ "data-terminal": "",
1049
+ "data-running": running ? "" : void 0,
1050
+ "data-body": body ? "" : void 0,
1051
+ children: [
1052
+ /* @__PURE__ */ jsxs2("div", { className: TerminalBlock_module_default.header, children: [
1053
+ /* @__PURE__ */ jsxs2("div", { className: TerminalBlock_module_default.prompt, children: [
1054
+ runStateDot && /* @__PURE__ */ jsx2("span", { className: TerminalBlock_module_default.runStateLabel, children: state.label }),
1055
+ commandLines.map((line, index) => /* @__PURE__ */ jsxs2("div", { className: TerminalBlock_module_default.promptLine, children: [
1056
+ index === 0 && runStateDot && /* @__PURE__ */ jsx2(StateDot, { state: state.state, className: TerminalBlock_module_default.runState }),
1057
+ /* @__PURE__ */ jsx2("span", { className: TerminalBlock_module_default.cwd, children: index > 0 || cwd === void 0 ? "$" : promptLabel(cwd, home) }),
1058
+ /* @__PURE__ */ jsx2("span", { className: TerminalBlock_module_default.command, children: line })
1059
+ ] }, index))
1060
+ ] }),
1061
+ status !== void 0 && /* @__PURE__ */ jsx2(Pill, { className: TerminalBlock_module_default.status, children: status }),
1062
+ (copyText4 !== void 0 || !running && !empty) && /* @__PURE__ */ jsx2("button", { type: "button", className: TerminalBlock_module_default.copyButton, onClick: onCopy, children: copied ? copy.copied : copy.copy })
1063
+ ] }),
1064
+ body && (empty ? /* @__PURE__ */ jsx2("div", { className: TerminalBlock_module_default.empty, children: copy.noOutput }) : /* @__PURE__ */ jsxs2("div", { className: TerminalBlock_module_default.output, children: [
1065
+ (capped ? lines.slice(0, headLines) : lines).map((line, index) => /* @__PURE__ */ jsx2("div", { className: TerminalBlock_module_default.line, children: renderLine(line) }, index)),
1066
+ hidden > 0 && /* @__PURE__ */ jsx2(
1067
+ "button",
1068
+ {
1069
+ type: "button",
1070
+ className: TerminalBlock_module_default.expand,
1071
+ "aria-expanded": expanded,
1072
+ "aria-label": expanded ? copy.collapseAria : copy.expandAria(hidden),
1073
+ onClick: onToggle,
1074
+ children: expanded ? copy.collapse : copy.expand(hidden)
1075
+ }
1076
+ ),
1077
+ capped && lines.slice(lines.length - tailLines).map((line, index) => /* @__PURE__ */ jsx2("div", { className: TerminalBlock_module_default.line, children: renderLine(line) }, index))
1078
+ ] }))
1079
+ ]
1080
+ }
1081
+ );
1082
+ }
1083
+
1084
+ // src/ReadBlock.tsx
1085
+ import { useCallback as useCallback4, useMemo as useMemo2, useRef as useRef2, useState as useState4, useSyncExternalStore as useSyncExternalStore2 } from "react";
1086
+ import clsx3 from "clsx";
1087
+
1088
+ // src/FoldToggle.tsx
1089
+ import { jsx as jsx3 } from "react/jsx-runtime";
1090
+ function FoldToggle({ className, expanded, hidden, labels, onToggle }) {
1091
+ return /* @__PURE__ */ jsx3(
1092
+ "button",
1093
+ {
1094
+ type: "button",
1095
+ className,
1096
+ "aria-expanded": expanded,
1097
+ "aria-label": expanded ? labels.collapseAria : labels.expandAria(hidden),
1098
+ onClick: onToggle,
1099
+ children: expanded ? labels.collapse : labels.expand(hidden)
1100
+ }
1101
+ );
1102
+ }
1103
+
1104
+ // .build/css/ReadBlock.module.mjs
1105
+ var id3 = "@seekbuddy/dsh-ui/ReadBlock.module.css";
1106
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id3 + '"]')) {
1107
+ const element = document.createElement("style");
1108
+ element.setAttribute("data-dsh-ui-primitives", id3);
1109
+ element.textContent = ".Lq5Aja_line{white-space:pre;min-height:1lh;display:flex}.Lq5Aja_gutter{width:var(--dsl-read-gutter);text-align:right;color:var(--dsw-alias-label-tertiary);user-select:none;flex:none;margin-right:12px}.Lq5Aja_content{min-width:0;color:var(--dsw-alias-label-primary)}.Lq5Aja_block[data-code-wrap=true] .Lq5Aja_line{white-space:pre-wrap}.Lq5Aja_block[data-code-wrap=true] .Lq5Aja_content{overflow-wrap:anywhere}.Lq5Aja_expand{width:100%;padding:0 0 0 calc(var(--dsl-read-gutter) + 12px);color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;text-align:left;background:0 0;border:none;display:block}.Lq5Aja_expand:hover{color:var(--dsw-alias-label-secondary)}";
1110
+ document.head.appendChild(element);
1111
+ }
1112
+ var ReadBlock_module_default = { "expand": "Lq5Aja_expand", "line": "Lq5Aja_line", "gutter": "Lq5Aja_gutter", "block": "Lq5Aja_block", "content": "Lq5Aja_content" };
1113
+
1114
+ // src/ReadBlock.tsx
1115
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1116
+ var DEFAULT_READ_MAX_LINES = 16;
1117
+ function renderSpans(spans) {
1118
+ return spans.map((span, index) => /* @__PURE__ */ jsx4("span", { style: span.style, children: span.text }, index));
1119
+ }
1120
+ function ReadBlock({
1121
+ label,
1122
+ labels,
1123
+ lines,
1124
+ totalLines,
1125
+ lang,
1126
+ maxLines = DEFAULT_READ_MAX_LINES,
1127
+ className
1128
+ }) {
1129
+ const rootRef = useRef2(null);
1130
+ const highlighting = useViewportHighlighting(rootRef, lang);
1131
+ const raw = useMemo2(() => lines.map((line) => line.text).join("\n"), [lines]);
1132
+ const loaded = useSyncExternalStore2(subscribeGrammarLoaded, grammarLoadCount, grammarLoadCount);
1133
+ const highlighted = useMemo2(
1134
+ () => highlighting ? highlightLines(raw, lang) : void 0,
1135
+ [highlighting, raw, lang, loaded]
1136
+ );
1137
+ const [expanded, setExpanded] = useState4(false);
1138
+ const [copied, setCopied] = useState4(false);
1139
+ const [wrapped, setWrapped] = useState4(false);
1140
+ const onCopy = useCallback4(() => {
1141
+ if (copied) return;
1142
+ void writeClipboard(raw).then((ok) => {
1143
+ if (!ok) return;
1144
+ setCopied(true);
1145
+ window.setTimeout(() => {
1146
+ setCopied(false);
1147
+ }, 1e3);
1148
+ });
1149
+ }, [copied, raw]);
1150
+ const onToggle = useCallback4(() => {
1151
+ setExpanded((value) => !value);
1152
+ }, []);
1153
+ const hidden = lines.length - maxLines;
1154
+ const capped = hidden > 0 && !expanded;
1155
+ const headLines = Math.ceil(maxLines / 2);
1156
+ const tailLines = maxLines - headLines;
1157
+ const windowed = lines.length < totalLines;
1158
+ const rows = (slice) => slice.map(([line, spans]) => /* @__PURE__ */ jsxs3("div", { className: ReadBlock_module_default.line, children: [
1159
+ /* @__PURE__ */ jsx4("span", { className: ReadBlock_module_default.gutter, "aria-hidden": true, children: line.number }),
1160
+ /* @__PURE__ */ jsx4("span", { className: ReadBlock_module_default.content, children: spans === void 0 ? line.text : renderSpans(spans) })
1161
+ ] }, line.number));
1162
+ const gutterDigits = lines.reduce((digits, line) => Math.max(digits, String(line.number).length), 3);
1163
+ const gutterStyle = { "--dsl-read-gutter": `${gutterDigits}ch` };
1164
+ const paired = lines.map((line, index) => [
1165
+ line,
1166
+ highlighted?.[index]
1167
+ ]);
1168
+ return /* @__PURE__ */ jsxs3(
1169
+ "div",
1170
+ {
1171
+ ref: rootRef,
1172
+ className: clsx3(CodeCard_module_default.card, ReadBlock_module_default.block, className),
1173
+ "data-read": "",
1174
+ "data-code-wrap": wrapped,
1175
+ style: gutterStyle,
1176
+ children: [
1177
+ /* @__PURE__ */ jsx4(
1178
+ CodeToolbar,
1179
+ {
1180
+ lang,
1181
+ title: label,
1182
+ status: windowed ? labels.window(lines.length, totalLines) : void 0,
1183
+ labels,
1184
+ copyLabel: labels.copy,
1185
+ copiedLabel: labels.copied,
1186
+ copied,
1187
+ wrapped,
1188
+ onCopy: lines.length > 0 ? onCopy : void 0,
1189
+ onWrap: () => {
1190
+ setWrapped((value) => !value);
1191
+ }
1192
+ }
1193
+ ),
1194
+ /* @__PURE__ */ jsxs3("div", { className: CodeCard_module_default.body, children: [
1195
+ rows(capped ? paired.slice(0, headLines) : paired),
1196
+ hidden > 0 && /* @__PURE__ */ jsx4(FoldToggle, { className: ReadBlock_module_default.expand, expanded, hidden, labels, onToggle }),
1197
+ capped && rows(paired.slice(paired.length - tailLines))
1198
+ ] })
1199
+ ]
1200
+ }
1201
+ );
1202
+ }
1203
+
1204
+ // src/DiffBlock.tsx
1205
+ import { useCallback as useCallback6, useMemo as useMemo3, useState as useState5 } from "react";
1206
+ import clsx4 from "clsx";
1207
+ import { structuredPatch } from "diff";
1208
+
1209
+ // src/code-highlighting.ts
1210
+ import { useCallback as useCallback5, useSyncExternalStore as useSyncExternalStore3 } from "react";
1211
+ import { CODE_HIGHLIGHT_EXTENSIONS, languageForPath } from "@deepseek-ai/dsh-util-code-language";
1212
+ function useCodeHighlighter(language) {
1213
+ const loaded = useSyncExternalStore3(subscribeGrammarLoaded, grammarLoadCount, grammarLoadCount);
1214
+ return useCallback5((code) => highlightLines(code, language), [language, loaded]);
1215
+ }
1216
+
1217
+ // .build/css/DiffBlock.module.mjs
1218
+ var id4 = "@seekbuddy/dsh-ui/DiffBlock.module.css";
1219
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id4 + '"]')) {
1220
+ const element = document.createElement("style");
1221
+ element.setAttribute("data-dsh-ui-primitives", id4);
1222
+ element.textContent = '.tEQPFa_block{overflow:hidden}.tEQPFa_body{font:var(--dsw-font-markdown-code-block);grid-template-columns:minmax(max-content,1fr);padding:6px 0 20px;display:grid;overflow-x:auto}.tEQPFa_line{box-sizing:border-box;white-space:pre;min-height:1lh;padding:0 22px}.tEQPFa_block[data-code-wrap=true] .tEQPFa_body{grid-template-columns:minmax(0,1fr)}.tEQPFa_block[data-code-wrap=true] .tEQPFa_line{white-space:pre-wrap;overflow-wrap:anywhere}.tEQPFa_path{color:var(--dsw-alias-label-secondary);font-weight:500}.tEQPFa_gap{color:var(--dsw-alias-label-tertiary)}.tEQPFa_del:before{content:"- "}.tEQPFa_del{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-code-diff-deleted);box-shadow:inset 3px 0 0 var(--dsw-alias-state-error-primary)}.tEQPFa_add:before{content:"+ "}.tEQPFa_add{color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-code-diff-added);box-shadow:inset 3px 0 0 var(--dsw-alias-state-success-primary)}.tEQPFa_context{color:var(--dsw-alias-label-secondary)}.tEQPFa_context:before{content:" "}.tEQPFa_expand{width:100%;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;text-align:left;background:0 0;border:none;padding:0 22px;display:block}.tEQPFa_expand:hover{color:var(--dsw-alias-label-secondary)}';
1223
+ document.head.appendChild(element);
1224
+ }
1225
+ var DiffBlock_module_default = { "body": "tEQPFa_body", "line": "tEQPFa_line", "context": "tEQPFa_context", "path": "tEQPFa_path", "expand": "tEQPFa_expand", "add": "tEQPFa_add", "block": "tEQPFa_block", "del": "tEQPFa_del", "gap": "tEQPFa_gap" };
1226
+
1227
+ // src/DiffBlock.tsx
1228
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1229
+ var DEFAULT_DIFF_MAX_LINES = 16;
1230
+ function assertNever(value) {
1231
+ throw new Error(`unreachable diff row kind: ${String(value)}`);
1232
+ }
1233
+ var ROW_CLASS = {
1234
+ path: DiffBlock_module_default.path,
1235
+ del: DiffBlock_module_default.del,
1236
+ add: DiffBlock_module_default.add,
1237
+ context: DiffBlock_module_default.context,
1238
+ gap: DiffBlock_module_default.gap
1239
+ };
1240
+ var MAX_DIFF_EDIT_LENGTH = 256;
1241
+ function localHunks(diff) {
1242
+ const oldLines = contentLines(diff.oldText ?? "");
1243
+ const newLines = contentLines(diff.newText);
1244
+ const normalize = (lines) => lines.map((line) => `${line}
1245
+ `).join("");
1246
+ return structuredPatch("", "", normalize(oldLines), normalize(newLines), void 0, void 0, {
1247
+ context: 3,
1248
+ maxEditLength: MAX_DIFF_EDIT_LENGTH
1249
+ })?.hunks ?? [{ lines: [...oldLines.map((line) => `-${line}`), ...newLines.map((line) => `+${line}`)] }];
1250
+ }
1251
+ function diffTotals(diffs) {
1252
+ let added = 0;
1253
+ let removed = 0;
1254
+ for (const diff of diffs) {
1255
+ for (const hunk of localHunks(diff)) {
1256
+ for (const line of hunk.lines) {
1257
+ if (line.startsWith("+")) added++;
1258
+ if (line.startsWith("-")) removed++;
1259
+ }
1260
+ }
1261
+ }
1262
+ return { added, removed };
1263
+ }
1264
+ function buildRows(diffs) {
1265
+ const rows = [];
1266
+ let prevPath;
1267
+ for (const diff of diffs) {
1268
+ if (diff.path !== prevPath) rows.push({ kind: "path", text: diff.path });
1269
+ else rows.push({ kind: "gap", text: "\u22EF" });
1270
+ prevPath = diff.path;
1271
+ for (const [index, hunk] of localHunks(diff).entries()) {
1272
+ if (index > 0) rows.push({ kind: "gap", text: "\u22EF" });
1273
+ for (const line of hunk.lines) {
1274
+ const kind = line.startsWith("-") ? "del" : line.startsWith("+") ? "add" : "context";
1275
+ rows.push({ kind, text: line.slice(1) });
1276
+ }
1277
+ }
1278
+ }
1279
+ return rows;
1280
+ }
1281
+ function contentLines(text) {
1282
+ if (text === "") return [];
1283
+ const body = text.endsWith("\n") ? text.slice(0, -1) : text;
1284
+ return body.split("\n");
1285
+ }
1286
+ function copyText2(rows) {
1287
+ return rows.map((row) => {
1288
+ switch (row.kind) {
1289
+ case "del":
1290
+ return `- ${row.text}`;
1291
+ case "add":
1292
+ return `+ ${row.text}`;
1293
+ case "context":
1294
+ return ` ${row.text}`;
1295
+ case "path":
1296
+ return row.text;
1297
+ case "gap":
1298
+ return row.text;
1299
+ /* v8 ignore next -- closed-union backstop; only reached if a row kind is forged */
1300
+ default:
1301
+ return assertNever(row.kind);
1302
+ }
1303
+ }).join("\n");
1304
+ }
1305
+ function DiffBlock({ diffs, labels, maxLines = DEFAULT_DIFF_MAX_LINES, className }) {
1306
+ const rows = useMemo3(() => buildRows(diffs), [diffs]);
1307
+ const [expanded, setExpanded] = useState5(false);
1308
+ const [copied, setCopied] = useState5(false);
1309
+ const [wrapped, setWrapped] = useState5(false);
1310
+ const firstLanguage = diffs[0] === void 0 ? void 0 : languageForPath(diffs[0].path);
1311
+ const language = diffs.every((diff) => languageForPath(diff.path) === firstLanguage) ? firstLanguage : void 0;
1312
+ const onCopy = useCallback6(() => {
1313
+ if (copied) return;
1314
+ void writeClipboard(copyText2(rows)).then((ok) => {
1315
+ if (!ok) return;
1316
+ setCopied(true);
1317
+ window.setTimeout(() => {
1318
+ setCopied(false);
1319
+ }, 1e3);
1320
+ });
1321
+ }, [copied, rows]);
1322
+ const onToggle = useCallback6(() => {
1323
+ setExpanded((value) => !value);
1324
+ }, []);
1325
+ if (rows.length === 0) return null;
1326
+ const hidden = rows.length - maxLines;
1327
+ const capped = hidden > 0 && !expanded;
1328
+ const headLines = Math.ceil(maxLines / 2);
1329
+ const tailLines = maxLines - headLines;
1330
+ const head = capped ? rows.slice(0, headLines) : rows;
1331
+ const tail = capped ? rows.slice(rows.length - tailLines) : [];
1332
+ return /* @__PURE__ */ jsxs4("div", { className: clsx4(CodeCard_module_default.card, DiffBlock_module_default.block, className), "data-diff": "", "data-code-wrap": wrapped, children: [
1333
+ /* @__PURE__ */ jsx5(
1334
+ CodeToolbar,
1335
+ {
1336
+ lang: language,
1337
+ labels,
1338
+ copyLabel: labels.copy,
1339
+ copiedLabel: labels.copied,
1340
+ copied,
1341
+ wrapped,
1342
+ onCopy,
1343
+ onWrap: () => {
1344
+ setWrapped((value) => !value);
1345
+ }
1346
+ }
1347
+ ),
1348
+ /* @__PURE__ */ jsxs4("div", { className: DiffBlock_module_default.body, children: [
1349
+ head.map((row, index) => /* @__PURE__ */ jsx5("div", { className: clsx4(DiffBlock_module_default.line, ROW_CLASS[row.kind]), children: row.text }, index)),
1350
+ hidden > 0 && /* @__PURE__ */ jsx5(FoldToggle, { className: DiffBlock_module_default.expand, expanded, hidden, labels, onToggle }),
1351
+ tail.map((row, index) => /* @__PURE__ */ jsx5("div", { className: clsx4(DiffBlock_module_default.line, ROW_CLASS[row.kind]), children: row.text }, index))
1352
+ ] })
1353
+ ] });
1354
+ }
1355
+
1356
+ // src/SearchBlock.tsx
1357
+ import { useCallback as useCallback7, useState as useState6 } from "react";
1358
+ import clsx5 from "clsx";
1359
+
1360
+ // .build/css/SearchBlock.module.mjs
1361
+ var id5 = "@seekbuddy/dsh-ui/SearchBlock.module.css";
1362
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id5 + '"]')) {
1363
+ const element = document.createElement("style");
1364
+ element.setAttribute("data-dsh-ui-primitives", id5);
1365
+ element.textContent = "._-soDW_block{--dsl-search-radius:var(--dsw-radius-lg);--dsl-search-line-height:22px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border-radius:var(--dsl-search-radius);margin:16px 0;position:relative}._-soDW_header{background:var(--dsw-alias-markdown-code-block-banner);border-top-left-radius:var(--dsl-search-radius);border-top-right-radius:var(--dsl-search-radius);align-items:center;gap:12px;padding:9px 14px;display:flex}._-soDW_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-secondary);flex:1;overflow:hidden}._-soDW_copyButton{color:var(--dsw-alias-label-secondary);cursor:pointer;font:var(--dsw-font-xs-13);background-color:#0000;border:none;flex:none;margin:0;padding:0}._-soDW_body{font:var(--dsw-font-markdown-code-block);padding:8px 14px 12px 0;overflow:auto hidden}._-soDW_line{min-height:var(--dsl-search-line-height);white-space:pre;padding-left:14px}._-soDW_lineNumber{color:var(--dsw-alias-label-tertiary)}._-soDW_fileHeader{width:100%;min-height:var(--dsl-search-line-height);cursor:pointer;font:inherit;text-align:left;background-color:#0000;border:none;align-items:baseline;gap:8px;padding:0 14px;display:flex}._-soDW_filePath{min-width:0;color:var(--dsw-alias-label-primary);white-space:pre;font-weight:600}._-soDW_fileCount{color:var(--dsw-alias-label-tertiary);flex:none}._-soDW_expand{width:100%;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;text-align:left;background-color:#0000;border:none;padding:0 14px;display:block}._-soDW_expand:hover{color:var(--dsw-alias-label-secondary)}._-soDW_empty{font:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 14px}";
1366
+ document.head.appendChild(element);
1367
+ }
1368
+ var SearchBlock_module_default = { "lineNumber": "_-soDW_lineNumber", "header": "_-soDW_header", "expand": "_-soDW_expand", "block": "_-soDW_block", "filePath": "_-soDW_filePath", "fileCount": "_-soDW_fileCount", "copyButton": "_-soDW_copyButton", "summary": "_-soDW_summary", "body": "_-soDW_body", "fileHeader": "_-soDW_fileHeader", "empty": "_-soDW_empty", "line": "_-soDW_line" };
1369
+
1370
+ // src/SearchBlock.tsx
1371
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1372
+ var DEFAULT_SEARCH_MAX_LINES = 16;
1373
+ function copyText3(props) {
1374
+ if (props.kind === "paths") return props.paths.join("\n");
1375
+ return props.files.map((file) => [file.path, ...file.matches.map((m) => `${m.lineNumber}: ${m.line}`)].join("\n")).join("\n\n");
1376
+ }
1377
+ function shownCount(props) {
1378
+ return props.kind === "paths" ? props.paths.length : props.files.reduce((sum, file) => sum + file.matches.length, 0);
1379
+ }
1380
+ function summaryText(props, shown, truncated, total) {
1381
+ return props.kind === "paths" ? props.labels.pathsSummary(shown, total, truncated) : props.labels.matchesSummary(shown, total, props.files.length, truncated);
1382
+ }
1383
+ function toRows(props, collapsed) {
1384
+ if (props.kind === "paths") return props.paths.map((path) => ({ type: "path", path }));
1385
+ const rows = [];
1386
+ props.files.forEach((file, index) => {
1387
+ const isCollapsed = collapsed.has(index);
1388
+ rows.push({ type: "file", path: file.path, count: file.matches.length, index, collapsed: isCollapsed });
1389
+ if (isCollapsed) return;
1390
+ for (const match of file.matches) {
1391
+ rows.push({
1392
+ type: "match",
1393
+ lineNumber: match.lineNumber,
1394
+ line: match.line,
1395
+ key: `${index}:${match.lineNumber}`,
1396
+ fileIndex: index
1397
+ });
1398
+ }
1399
+ });
1400
+ return rows;
1401
+ }
1402
+ function rowKey(row) {
1403
+ switch (row.type) {
1404
+ case "match":
1405
+ return `match:${row.key}`;
1406
+ case "file":
1407
+ return `file:${row.index}`;
1408
+ case "path":
1409
+ return `path:${row.path}`;
1410
+ }
1411
+ }
1412
+ function SearchBlock(props) {
1413
+ const { truncated, total, maxLines = DEFAULT_SEARCH_MAX_LINES, className } = props;
1414
+ const [expanded, setExpanded] = useState6(false);
1415
+ const [collapsed, setCollapsed] = useState6(() => /* @__PURE__ */ new Set());
1416
+ const rows = toRows(props, collapsed);
1417
+ const shown = shownCount(props);
1418
+ const empty = rows.length === 0;
1419
+ const { copied, onCopy } = useCopyFeedback(copyText3(props));
1420
+ const onToggle = useCallback7(() => {
1421
+ setExpanded((value) => !value);
1422
+ }, []);
1423
+ const toggleFile = useCallback7((index) => {
1424
+ setCollapsed((prev) => {
1425
+ const next = new Set(prev);
1426
+ if (next.has(index)) next.delete(index);
1427
+ else next.add(index);
1428
+ return next;
1429
+ });
1430
+ }, []);
1431
+ const { hidden, capped, headLines, tailLines } = headTailCap(rows.length, maxLines, expanded);
1432
+ const head = capped ? rows.slice(0, headLines) : rows;
1433
+ const naturalTail = capped ? rows.slice(rows.length - tailLines) : [];
1434
+ const tailLead = naturalTail[0];
1435
+ const tailHeader = tailLead?.type === "match" && !head.some((row) => row.type === "file" && row.index === tailLead.fileIndex) ? rows.find(
1436
+ (row) => row.type === "file" && row.index === tailLead.fileIndex
1437
+ ) : void 0;
1438
+ const tail = tailHeader === void 0 ? naturalTail : naturalTail.slice(1);
1439
+ const renderRow = (row) => {
1440
+ if (row.type === "path") return /* @__PURE__ */ jsx6("div", { className: SearchBlock_module_default.line, children: row.path });
1441
+ if (row.type === "match") {
1442
+ return /* @__PURE__ */ jsxs5("div", { className: SearchBlock_module_default.line, children: [
1443
+ /* @__PURE__ */ jsxs5("span", { className: SearchBlock_module_default.lineNumber, children: [
1444
+ row.lineNumber,
1445
+ ": "
1446
+ ] }),
1447
+ row.line
1448
+ ] });
1449
+ }
1450
+ return /* @__PURE__ */ jsxs5(
1451
+ "button",
1452
+ {
1453
+ type: "button",
1454
+ className: SearchBlock_module_default.fileHeader,
1455
+ "aria-expanded": !row.collapsed,
1456
+ onClick: () => {
1457
+ toggleFile(row.index);
1458
+ },
1459
+ children: [
1460
+ /* @__PURE__ */ jsx6("span", { className: SearchBlock_module_default.filePath, children: row.path }),
1461
+ /* @__PURE__ */ jsx6("span", { className: SearchBlock_module_default.fileCount, children: row.count })
1462
+ ]
1463
+ }
1464
+ );
1465
+ };
1466
+ return /* @__PURE__ */ jsxs5("div", { className: clsx5(SearchBlock_module_default.block, className), "data-search": props.kind, children: [
1467
+ /* @__PURE__ */ jsxs5("div", { className: SearchBlock_module_default.header, children: [
1468
+ /* @__PURE__ */ jsx6("span", { className: SearchBlock_module_default.summary, children: summaryText(props, shown, truncated, total) }),
1469
+ !empty && /* @__PURE__ */ jsx6("button", { type: "button", className: SearchBlock_module_default.copyButton, onClick: onCopy, children: copied ? props.labels.copied : props.labels.copy })
1470
+ ] }),
1471
+ empty ? /* @__PURE__ */ jsx6("div", { className: SearchBlock_module_default.empty, children: props.labels.noResults }) : /* @__PURE__ */ jsxs5("div", { className: SearchBlock_module_default.body, children: [
1472
+ head.map((row) => /* @__PURE__ */ jsx6("div", { children: renderRow(row) }, rowKey(row))),
1473
+ hidden > 0 && /* @__PURE__ */ jsx6(
1474
+ "button",
1475
+ {
1476
+ type: "button",
1477
+ className: SearchBlock_module_default.expand,
1478
+ "aria-expanded": expanded,
1479
+ "aria-label": expanded ? props.labels.collapseAria : props.labels.expandAria(hidden),
1480
+ onClick: onToggle,
1481
+ children: expanded ? props.labels.collapse : props.labels.expand(hidden)
1482
+ }
1483
+ ),
1484
+ tailHeader !== void 0 && /* @__PURE__ */ jsx6("div", { children: renderRow(tailHeader) }, `tailHeader:${rowKey(tailHeader)}`),
1485
+ tail.map((row) => /* @__PURE__ */ jsx6("div", { children: renderRow(row) }, rowKey(row)))
1486
+ ] })
1487
+ ] });
1488
+ }
1489
+
1490
+ // src/WebBlock.tsx
1491
+ import clsx6 from "clsx";
1492
+
1493
+ // .build/css/WebBlock.module.mjs
1494
+ var id6 = "@seekbuddy/dsh-ui/WebBlock.module.css";
1495
+ if (typeof document !== "undefined" && !document.querySelector('style[data-dsh-ui-primitives="' + id6 + '"]')) {
1496
+ const element = document.createElement("style");
1497
+ element.setAttribute("data-dsh-ui-primitives", id6);
1498
+ element.textContent = ".MTeYQa_block{--dsl-web-radius:var(--dsw-radius-lg);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border-radius:var(--dsl-web-radius);margin:16px 0;padding:12px 14px}.MTeYQa_answer{margin-bottom:8px}.MTeYQa_answer>div>:first-child{margin-top:0}.MTeYQa_answer>div>:last-child{margin-bottom:0}.MTeYQa_sources{flex-direction:column;gap:10px;max-height:320px;margin:0;padding-left:2.5em;display:flex;overflow-y:auto}.MTeYQa_source{min-width:0}.MTeYQa_sourceLink{color:var(--dsw-alias-link);word-break:break-word;font-size:14px;font-weight:500;line-height:20px;text-decoration:none}.MTeYQa_linkIcon{vertical-align:-.25em;width:1.1em;height:1.1em;margin-right:5px}.MTeYQa_sourceLink:hover,.MTeYQa_sourceLink:focus-visible{text-underline-offset:3px;text-decoration:underline dotted}.MTeYQa_snippet{color:var(--dsw-alias-label-secondary);word-break:break-word;margin-top:2px;font-size:13px;line-height:19px}.MTeYQa_published{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xs-13);margin-top:2px}.MTeYQa_truncated{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xs-13);margin-top:8px}.MTeYQa_empty{color:var(--dsw-alias-label-secondary);font:var(--dsw-font-xs-13)}.MTeYQa_fetch{flex-direction:column;gap:6px;display:flex}.MTeYQa_fetchUrl{color:var(--dsw-alias-link);font-family:var(--ds-font-family-code);word-break:break-all;font-size:13px;font-weight:500;line-height:19px;text-decoration:none}.MTeYQa_fetchUrl:hover,.MTeYQa_fetchUrl:focus-visible{text-underline-offset:3px;text-decoration:underline dotted}.MTeYQa_fetchMeta{align-items:baseline;gap:12px;display:flex}.MTeYQa_status{color:var(--dsw-alias-label-secondary);font:var(--dsw-font-xs-13)}.MTeYQa_fetch .MTeYQa_truncated{margin-top:0}";
1499
+ document.head.appendChild(element);
1500
+ }
1501
+ var WebBlock_module_default = { "empty": "MTeYQa_empty", "fetchUrl": "MTeYQa_fetchUrl", "status": "MTeYQa_status", "sourceLink": "MTeYQa_sourceLink", "fetch": "MTeYQa_fetch", "published": "MTeYQa_published", "block": "MTeYQa_block", "snippet": "MTeYQa_snippet", "source": "MTeYQa_source", "truncated": "MTeYQa_truncated", "fetchMeta": "MTeYQa_fetchMeta", "sources": "MTeYQa_sources", "linkIcon": "MTeYQa_linkIcon", "answer": "MTeYQa_answer" };
1502
+
1503
+ // src/WebBlock.tsx
1504
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1505
+ function safeHref(url) {
1506
+ try {
1507
+ const { protocol } = new URL(url);
1508
+ return protocol === "http:" || protocol === "https:" ? url : void 0;
1509
+ } catch {
1510
+ return void 0;
1511
+ }
1512
+ }
1513
+ function linkLabel(url, title) {
1514
+ if (title !== void 0 && title !== "") return title;
1515
+ try {
1516
+ const { hostname } = new URL(url);
1517
+ return hostname === "" ? url : hostname;
1518
+ } catch {
1519
+ return url;
1520
+ }
1521
+ }
1522
+ function SafeLink({ url, label, className }) {
1523
+ const href = safeHref(url);
1524
+ if (href === void 0) return /* @__PURE__ */ jsx7("span", { className, children: label });
1525
+ return /* @__PURE__ */ jsxs6("a", { className, href, target: "_blank", rel: "noopener noreferrer", children: [
1526
+ /* @__PURE__ */ jsx7(LinkIconMedium, { kind: "url", href, className: WebBlock_module_default.linkIcon }),
1527
+ label
1528
+ ] });
1529
+ }
1530
+ function SourceItem({ source, ordinal }) {
1531
+ return /* @__PURE__ */ jsxs6("li", { className: WebBlock_module_default.source, value: ordinal, children: [
1532
+ /* @__PURE__ */ jsx7(SafeLink, { url: source.url, label: linkLabel(source.url, source.title), className: WebBlock_module_default.sourceLink }),
1533
+ source.snippet !== void 0 && source.snippet !== "" && /* @__PURE__ */ jsx7("div", { className: WebBlock_module_default.snippet, children: source.snippet }),
1534
+ source.publishedAt !== void 0 && source.publishedAt !== "" && /* @__PURE__ */ jsx7("div", { className: WebBlock_module_default.published, children: source.publishedAt })
1535
+ ] });
1536
+ }
1537
+ function WebSearchBlock({ answer, sources, truncated, labels, className }) {
1538
+ const empty = (answer === void 0 || answer === "") && sources.length === 0;
1539
+ return /* @__PURE__ */ jsxs6("div", { className: clsx6(WebBlock_module_default.block, className), "data-web": "search", children: [
1540
+ answer !== void 0 && answer !== "" && /* @__PURE__ */ jsx7("div", { className: WebBlock_module_default.answer, children: /* @__PURE__ */ jsx7(MarkdownText, { text: answer, labels: labels.markdown }) }),
1541
+ empty ? /* @__PURE__ */ jsx7("div", { className: WebBlock_module_default.empty, children: labels.noResults }) : /* @__PURE__ */ jsx7("ol", { className: WebBlock_module_default.sources, children: sources.map((source, index) => /* @__PURE__ */ jsx7(SourceItem, { source, ordinal: index + 1 }, index)) }),
1542
+ truncated && /* @__PURE__ */ jsx7("div", { className: WebBlock_module_default.truncated, children: labels.sourcesTruncated })
1543
+ ] });
1544
+ }
1545
+ function WebFetchBlock({ url, statusCode, truncated, labels, className }) {
1546
+ return /* @__PURE__ */ jsxs6("div", { className: clsx6(WebBlock_module_default.block, WebBlock_module_default.fetch, className), "data-web": "fetch", children: [
1547
+ /* @__PURE__ */ jsx7(SafeLink, { url, label: url, className: WebBlock_module_default.fetchUrl }),
1548
+ /* @__PURE__ */ jsxs6("div", { className: WebBlock_module_default.fetchMeta, children: [
1549
+ /* @__PURE__ */ jsxs6("span", { className: WebBlock_module_default.status, children: [
1550
+ labels.http,
1551
+ " ",
1552
+ statusCode
1553
+ ] }),
1554
+ truncated && /* @__PURE__ */ jsx7("span", { className: WebBlock_module_default.truncated, children: labels.contentTruncated })
1555
+ ] })
1556
+ ] });
1557
+ }
1558
+ function WebBlock(props) {
1559
+ return props.kind === "search" ? /* @__PURE__ */ jsx7(WebSearchBlock, { ...props }) : /* @__PURE__ */ jsx7(WebFetchBlock, { ...props });
1560
+ }
1561
+ export {
1562
+ CODE_HIGHLIGHT_EXTENSIONS,
1563
+ DEFAULT_DIFF_MAX_LINES,
1564
+ DEFAULT_READ_MAX_LINES,
1565
+ DEFAULT_SEARCH_MAX_LINES,
1566
+ DEFAULT_TERMINAL_MAX_LINES,
1567
+ DiffBlock,
1568
+ FileTypeIcon,
1569
+ JsonTree,
1570
+ LinkIconMedium,
1571
+ LinkIconRegular,
1572
+ ReadBlock,
1573
+ SearchBlock,
1574
+ TerminalBlock,
1575
+ WebBlock,
1576
+ classifyFileType,
1577
+ classifyLinkPath,
1578
+ diffTotals,
1579
+ fileExtension,
1580
+ languageForPath,
1581
+ useCodeHighlighter
1582
+ };