@openviking/react 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/README.md +18 -15
  2. package/dist/1~0.js +506 -0
  3. package/dist/2~0.js +122 -0
  4. package/dist/30~0.js +1332 -0
  5. package/dist/3~0.js +2113 -4
  6. package/dist/ark-message-list-view~0.js +310 -0
  7. package/dist/c7~0.js +24 -0
  8. package/dist/client/index.d.ts +2 -1
  9. package/dist/client/paths.d.ts +64 -0
  10. package/dist/client/response.d.ts +31 -0
  11. package/dist/client/sse.d.ts +39 -0
  12. package/dist/client/stream.d.ts +26 -0
  13. package/dist/client/types.d.ts +104 -0
  14. package/dist/client.js +1 -239
  15. package/dist/components/agent-connect/agent-connect-copy.d.ts +34 -0
  16. package/dist/components/agent-connect/agent-connect-design.d.ts +1781 -0
  17. package/dist/components/agent-connect/agent-connect-detail.d.ts +13 -0
  18. package/dist/components/agent-connect/agent-connect-installer.d.ts +3 -0
  19. package/dist/components/agent-connect/agent-connect-instructions-view.d.ts +14 -0
  20. package/dist/components/agent-connect/agent-connect-instructions.d.ts +145 -0
  21. package/dist/components/agent-connect/agent-connect-markdown.d.ts +3 -0
  22. package/dist/components/agent-connect/agent-connect.d.ts +3 -3
  23. package/dist/components/agent-connect/content-en.d.ts +137 -0
  24. package/dist/components/agent-connect/content-zh.d.ts +137 -0
  25. package/dist/components/agent-connect/style.css +495 -6
  26. package/dist/components/agent-connect/types.d.ts +20 -166
  27. package/dist/components/file-browser-entries/file-browser-entries-icons.d.ts +18 -0
  28. package/dist/components/file-browser-entries/file-browser-entries.d.ts +14 -0
  29. package/dist/components/file-browser-entries/index.d.ts +1 -0
  30. package/dist/components/file-browser-entries/style.css +155 -0
  31. package/dist/components/file-browser-entries/types.d.ts +45 -0
  32. package/dist/components/file-browser-entries.js +1 -0
  33. package/dist/components/file-preview/file-preview-adapters.d.ts +33 -0
  34. package/dist/components/file-preview/file-preview-body.d.ts +24 -12
  35. package/dist/components/file-preview/file-preview-breadcrumb-menu.d.ts +16 -0
  36. package/dist/components/file-preview/file-preview-breadcrumb.d.ts +21 -0
  37. package/dist/components/file-preview/file-preview-copy-path.d.ts +12 -0
  38. package/dist/components/file-preview/file-preview-directory.d.ts +32 -0
  39. package/dist/components/file-preview/file-preview-editor.d.ts +22 -0
  40. package/dist/components/file-preview/file-preview-handle-adapters.d.ts +26 -0
  41. package/dist/components/file-preview/file-preview-header.d.ts +41 -14
  42. package/dist/components/file-preview/file-preview-labels.d.ts +15 -4
  43. package/dist/components/file-preview/file-preview-lazy-viewer.d.ts +3 -0
  44. package/dist/components/file-preview/file-preview-panels.d.ts +41 -0
  45. package/dist/components/file-preview/file-preview-path.d.ts +30 -0
  46. package/dist/components/file-preview/file-preview-source.d.ts +24 -0
  47. package/dist/components/file-preview/file-preview-state.d.ts +35 -0
  48. package/dist/components/file-preview/file-preview-tab-row.d.ts +16 -0
  49. package/dist/components/file-preview/file-preview-viewer.d.ts +31 -0
  50. package/dist/components/file-preview/file-preview.d.ts +9 -11
  51. package/dist/components/file-preview/level-selection.d.ts +25 -0
  52. package/dist/components/file-preview/style.css +4055 -126
  53. package/dist/components/file-preview/types.d.ts +350 -170
  54. package/dist/components/file-preview/use-directory-level.d.ts +30 -0
  55. package/dist/components/file-preview/use-file-preview-actions-context.d.ts +27 -0
  56. package/dist/components/file-preview/use-file-preview-actions.d.ts +19 -0
  57. package/dist/components/file-preview/use-file-preview-editing.d.ts +21 -2
  58. package/dist/components/file-preview/use-file-preview-ids.d.ts +24 -0
  59. package/dist/components/file-preview.js +1 -442
  60. package/dist/components/file-tree/file-tree-body.d.ts +8 -4
  61. package/dist/components/file-tree/file-tree-entry-row.d.ts +9 -3
  62. package/dist/components/file-tree/file-tree-icons.d.ts +12 -5
  63. package/dist/components/file-tree/file-tree-info-labels.d.ts +21 -0
  64. package/dist/components/file-tree/file-tree-info-tooltip.d.ts +43 -0
  65. package/dist/components/file-tree/file-tree-info.d.ts +29 -0
  66. package/dist/components/file-tree/file-tree-keyboard.d.ts +8 -4
  67. package/dist/components/file-tree/file-tree-row-context.d.ts +29 -12
  68. package/dist/components/file-tree/file-tree-row-shared.d.ts +18 -0
  69. package/dist/components/file-tree/file-tree-spinner.d.ts +10 -0
  70. package/dist/components/file-tree/file-tree-state-row.d.ts +7 -0
  71. package/dist/components/file-tree/file-tree-tooltip-surface.d.ts +22 -0
  72. package/dist/components/file-tree/file-tree.d.ts +12 -1
  73. package/dist/components/file-tree/style.css +280 -75
  74. package/dist/components/file-tree/types.d.ts +203 -0
  75. package/dist/components/file-tree/use-file-tree-actions.d.ts +7 -0
  76. package/dist/components/file-tree.js +1 -1
  77. package/dist/components/scope-switcher/scope-panel.d.ts +9 -3
  78. package/dist/components/scope-switcher/scope-selector.d.ts +1 -1
  79. package/dist/components/scope-switcher/scope-switcher.d.ts +1 -1
  80. package/dist/components/scope-switcher/style.css +282 -76
  81. package/dist/components/scope-switcher/types.d.ts +230 -108
  82. package/dist/components/style.css +14128 -390
  83. package/dist/components/tui/command-catalog.d.ts +58 -0
  84. package/dist/components/tui/command-completion.d.ts +19 -0
  85. package/dist/components/tui/command-definitions.d.ts +10 -0
  86. package/dist/components/tui/command-input.d.ts +16 -0
  87. package/dist/components/tui/style.css +1543 -5
  88. package/dist/components/tui/tui-assist.d.ts +15 -0
  89. package/dist/components/tui/tui-code-block.d.ts +8 -0
  90. package/dist/components/tui/tui-command-help.d.ts +9 -0
  91. package/dist/components/tui/tui-command-text.d.ts +6 -0
  92. package/dist/components/tui/tui-composer.d.ts +24 -0
  93. package/dist/components/tui/tui-copy-button.d.ts +9 -0
  94. package/dist/components/tui/tui-input-mirror.d.ts +14 -0
  95. package/dist/components/tui/tui-labels-zh.d.ts +2 -0
  96. package/dist/components/tui/tui-labels.d.ts +5 -0
  97. package/dist/components/tui/tui-markdown-renderers.d.ts +10 -0
  98. package/dist/components/tui/tui-markdown.d.ts +6 -0
  99. package/dist/components/tui/tui-param-hint.d.ts +7 -0
  100. package/dist/components/tui/tui-record-time.d.ts +11 -0
  101. package/dist/components/tui/tui-record.d.ts +13 -0
  102. package/dist/components/tui/tui-resource-preview.d.ts +10 -0
  103. package/dist/components/tui/tui-resource-tree.d.ts +10 -0
  104. package/dist/components/tui/tui-result-header.d.ts +7 -0
  105. package/dist/components/tui/tui-result-text.d.ts +5 -0
  106. package/dist/components/tui/tui-search-list.d.ts +8 -0
  107. package/dist/components/tui/tui-skeleton.d.ts +6 -0
  108. package/dist/components/tui/tui-status-card.d.ts +7 -0
  109. package/dist/components/tui/tui-text.d.ts +10 -0
  110. package/dist/components/tui/tui-uri-text.d.ts +19 -0
  111. package/dist/components/tui/tui-write-result.d.ts +7 -0
  112. package/dist/components/tui/tui.d.ts +10 -2
  113. package/dist/components/tui/types.d.ts +57 -15
  114. package/dist/components/tui/use-tui-assist-position.d.ts +3 -0
  115. package/dist/components/tui/use-tui-completion.d.ts +14 -0
  116. package/dist/components/tui/use-tui-composer-keyboard.d.ts +25 -0
  117. package/dist/components/viking-bot/ark-adapter.d.ts +45 -0
  118. package/dist/components/viking-bot/ark-message-body.d.ts +16 -0
  119. package/dist/components/viking-bot/ark-message-list-view.d.ts +7 -0
  120. package/dist/components/viking-bot/ark-message-row.d.ts +19 -0
  121. package/dist/components/viking-bot/index.d.ts +10 -0
  122. package/dist/components/viking-bot/interaction/ask-human-fields.d.ts +10 -0
  123. package/dist/components/viking-bot/interaction/index.d.ts +4 -0
  124. package/dist/components/viking-bot/interaction/labels.d.ts +7 -0
  125. package/dist/components/viking-bot/interaction/lazy-interaction.d.ts +3 -0
  126. package/dist/components/viking-bot/interaction/schedule-input.d.ts +13 -0
  127. package/dist/components/viking-bot/interaction/style.css +189 -0
  128. package/dist/components/viking-bot/interaction/style.js +0 -0
  129. package/dist/components/viking-bot/interaction/types.d.ts +188 -0
  130. package/dist/components/viking-bot/interaction/viking-bot-interaction.d.ts +9 -0
  131. package/dist/components/viking-bot/interaction.js +2 -0
  132. package/dist/components/viking-bot/labels.d.ts +2 -0
  133. package/dist/components/viking-bot/lazy-composer.d.ts +3 -0
  134. package/dist/components/viking-bot/message-groups.d.ts +12 -0
  135. package/dist/components/viking-bot/model.d.ts +252 -0
  136. package/dist/components/viking-bot/render-part.d.ts +12 -0
  137. package/dist/components/viking-bot/style.css +7135 -0
  138. package/dist/components/viking-bot/style.js +0 -0
  139. package/dist/components/viking-bot/types.d.ts +140 -0
  140. package/dist/components/viking-bot/viking-bot-composer.d.ts +6 -0
  141. package/dist/components/viking-bot/viking-bot-message-list.d.ts +3 -0
  142. package/dist/components/viking-bot/viking-bot.d.ts +16 -0
  143. package/dist/components/viking-bot.js +4 -0
  144. package/dist/c~0.js +201 -0
  145. package/dist/file-preview-viewer~0.js +191 -0
  146. package/dist/f~0.js +149 -77
  147. package/dist/h~0.js +58 -0
  148. package/dist/icons/file-type-icon.d.ts +31 -0
  149. package/dist/icons/index.d.ts +33 -23
  150. package/dist/icons/nextjs-icon.d.ts +19 -0
  151. package/dist/icons.js +1 -25
  152. package/dist/index.d.ts +4 -2
  153. package/dist/index.js +2 -1
  154. package/dist/k~0.js +1440 -0
  155. package/dist/lk~0.js +25 -12
  156. package/dist/l~0.js +1464 -25
  157. package/dist/modules/console/style.css +83 -1
  158. package/dist/modules/file-browser/file-browser-detail-icons.d.ts +10 -0
  159. package/dist/modules/file-browser/file-browser-detail.d.ts +33 -0
  160. package/dist/modules/file-browser/file-browser-empty.d.ts +3 -0
  161. package/dist/modules/file-browser/file-browser-failure.d.ts +22 -0
  162. package/dist/modules/file-browser/file-browser-icons.d.ts +18 -0
  163. package/dist/modules/file-browser/file-browser-labels.d.ts +28 -0
  164. package/dist/modules/file-browser/file-browser-layout.d.ts +27 -0
  165. package/dist/modules/file-browser/file-browser-toolbar.d.ts +18 -0
  166. package/dist/modules/file-browser/file-browser-tree-pane.d.ts +30 -0
  167. package/dist/modules/file-browser/file-browser.d.ts +14 -5
  168. package/dist/modules/file-browser/find-result.d.ts +24 -0
  169. package/dist/modules/file-browser/fs-directories.d.ts +33 -0
  170. package/dist/modules/file-browser/fs-file-kind.d.ts +19 -0
  171. package/dist/modules/file-browser/fs-icon.d.ts +17 -0
  172. package/dist/modules/file-browser/fs-model.d.ts +106 -0
  173. package/dist/modules/file-browser/fs-page.d.ts +16 -0
  174. package/dist/modules/file-browser/fs-path.d.ts +16 -0
  175. package/dist/modules/file-browser/fs-read-directory.d.ts +20 -0
  176. package/dist/modules/file-browser/fs-scope.d.ts +22 -0
  177. package/dist/modules/file-browser/fs-stat.d.ts +25 -0
  178. package/dist/modules/file-browser/index.d.ts +3 -1
  179. package/dist/modules/file-browser/style.css +5009 -34
  180. package/dist/modules/file-browser/tree-info-copy.d.ts +15 -0
  181. package/dist/modules/file-browser/tree-info-copy.zh-CN.d.ts +15 -0
  182. package/dist/modules/file-browser/types.d.ts +189 -44
  183. package/dist/modules/file-browser/use-container-width.d.ts +17 -0
  184. package/dist/modules/file-browser/use-file-browser.d.ts +49 -0
  185. package/dist/modules/file-browser/use-fs-preview.d.ts +51 -0
  186. package/dist/modules/file-browser/use-fs-search.d.ts +35 -0
  187. package/dist/modules/file-browser/use-fs-tree.d.ts +43 -0
  188. package/dist/modules/file-browser/use-request-scope.d.ts +39 -0
  189. package/dist/modules/file-browser.js +1 -1
  190. package/dist/modules/scope-cascade/style.css +282 -76
  191. package/dist/modules/style.css +5445 -130
  192. package/dist/n~0.js +568 -236
  193. package/dist/o~0.js +103 -0
  194. package/dist/shared/components/divider/divider.d.ts +18 -0
  195. package/dist/shared/components/divider/index.d.ts +1 -0
  196. package/dist/shared/components/divider/types.d.ts +35 -0
  197. package/dist/shared/components/overlay/types.d.ts +7 -0
  198. package/dist/shared/components/overlay/use-overlay-position.d.ts +38 -0
  199. package/dist/shared/components/popover/index.d.ts +1 -0
  200. package/dist/shared/components/popover/popover.d.ts +23 -0
  201. package/dist/shared/components/popover/types.d.ts +50 -0
  202. package/dist/shared/components/resizable/clamp.d.ts +13 -0
  203. package/dist/shared/components/resizable/index.d.ts +2 -0
  204. package/dist/shared/components/resizable/resizable-handle.d.ts +25 -0
  205. package/dist/shared/components/resizable/types.d.ts +48 -0
  206. package/dist/shared/components/tooltip/index.d.ts +1 -0
  207. package/dist/shared/components/tooltip/tooltip.d.ts +25 -0
  208. package/dist/shared/components/tooltip/types.d.ts +42 -0
  209. package/dist/style.css +19664 -530
  210. package/dist/u~0.js +1597 -4
  211. package/dist/viking-bot-composer~0.js +164 -0
  212. package/dist/viking-bot-interaction~0.js +284 -0
  213. package/dist/w~0.js +19 -0
  214. package/package.json +23 -10
  215. package/dist/components/file-preview/file-preview-icons.d.ts +0 -2
  216. package/dist/components/file-preview/file-preview-operations.d.ts +0 -1
  217. package/dist/components/file-tree/file-tree-dom.d.ts +0 -4
  218. package/dist/components/file-tree/file-tree-labels.d.ts +0 -5
  219. package/dist/components/file-tree/file-tree-rows.d.ts +0 -12
  220. package/dist/components/file-tree/file-tree-tooltip.d.ts +0 -11
  221. package/dist/i~0.js +0 -21
  222. package/dist/modules/file-browser/file-browser-toolbar-button.d.ts +0 -10
  223. package/dist/modules/task-center/columns.d.ts +0 -129
  224. package/dist/modules/task-center/index.d.ts +0 -1
  225. package/dist/modules/task-center/style.css +0 -29
  226. package/dist/modules/task-center/task-center.d.ts +0 -4
  227. package/dist/modules/task-center/types.d.ts +0 -168
  228. package/dist/modules/task-center.js +0 -1
  229. /package/dist/{modules/task-center → components/file-browser-entries}/style.js +0 -0
package/dist/30~0.js ADDED
@@ -0,0 +1,1332 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment as external_react_Fragment, Suspense, cloneElement, forwardRef, lazy, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { useOverlayPosition } from "./o~0.js";
5
+ function FilePreviewEditor({ draft, text, loading, failed, saveFailed, saving, onChange, onCancel }) {
6
+ if (loading) return /*#__PURE__*/ jsx("div", {
7
+ className: "ov-file-preview__state",
8
+ role: "status",
9
+ children: /*#__PURE__*/ jsx("p", {
10
+ className: "ov-file-preview__state-title",
11
+ children: text.loading
12
+ })
13
+ });
14
+ if (failed) return /*#__PURE__*/ jsxs("div", {
15
+ className: "ov-file-preview__state",
16
+ role: "alert",
17
+ children: [
18
+ /*#__PURE__*/ jsx("p", {
19
+ className: "ov-file-preview__state-title",
20
+ children: text.loadFailed
21
+ }),
22
+ /*#__PURE__*/ jsx("button", {
23
+ type: "button",
24
+ className: "ov-file-preview__button",
25
+ onClick: onCancel,
26
+ children: text.leaveEditing
27
+ })
28
+ ]
29
+ });
30
+ return /*#__PURE__*/ jsxs("div", {
31
+ className: "ov-file-preview__editor",
32
+ children: [
33
+ /*#__PURE__*/ jsx("textarea", {
34
+ className: "ov-file-preview__textarea",
35
+ value: draft,
36
+ readOnly: saving,
37
+ "aria-label": text.editor,
38
+ spellCheck: false,
39
+ onChange: (event)=>onChange(event.target.value)
40
+ }),
41
+ saveFailed ? /*#__PURE__*/ jsx("p", {
42
+ className: "ov-file-preview__notice",
43
+ role: "alert",
44
+ children: text.saveFailed
45
+ }) : null
46
+ ]
47
+ });
48
+ }
49
+ function encodeText(content) {
50
+ return new TextEncoder().encode(content);
51
+ }
52
+ function toFileSource(source) {
53
+ const { content, file, url, fileName, fileType } = source;
54
+ if ('string' == typeof content) return {
55
+ kind: 'bytes',
56
+ bytes: encodeText(content),
57
+ name: fileName,
58
+ ...fileType ? {
59
+ fileType
60
+ } : {}
61
+ };
62
+ if (file) return {
63
+ kind: 'file',
64
+ file: file instanceof File ? file : new File([
65
+ file
66
+ ], fileName),
67
+ name: fileName,
68
+ ...fileType ? {
69
+ fileType
70
+ } : {}
71
+ };
72
+ if (url) return {
73
+ kind: 'url',
74
+ url,
75
+ name: fileName,
76
+ ...fileType ? {
77
+ fileType
78
+ } : {}
79
+ };
80
+ }
81
+ function readCopyableText(source) {
82
+ const { content } = source;
83
+ return 'string' == typeof content && content.length > 0 ? content : void 0;
84
+ }
85
+ function isEmptyFile(source) {
86
+ return '' === source.content;
87
+ }
88
+ function StatePanel({ title, description, action, icon }) {
89
+ return /*#__PURE__*/ jsxs("div", {
90
+ className: "ov-file-preview__state",
91
+ role: "status",
92
+ children: [
93
+ icon,
94
+ /*#__PURE__*/ jsx("p", {
95
+ className: "ov-file-preview__state-title",
96
+ children: title
97
+ }),
98
+ description ? /*#__PURE__*/ jsx("p", {
99
+ className: "ov-file-preview__state-description",
100
+ children: description
101
+ }) : null,
102
+ action
103
+ ]
104
+ });
105
+ }
106
+ function EmptyFileState({ text }) {
107
+ return /*#__PURE__*/ jsx(StatePanel, {
108
+ title: text.fileEmpty
109
+ });
110
+ }
111
+ function LoadingState({ text }) {
112
+ return /*#__PURE__*/ jsx(StatePanel, {
113
+ title: text.loading ?? 'Loading…',
114
+ icon: /*#__PURE__*/ jsx("span", {
115
+ className: "ov-file-preview__spinner"
116
+ })
117
+ });
118
+ }
119
+ function LoadFailedState({ text, description, onRetry }) {
120
+ return /*#__PURE__*/ jsx(StatePanel, {
121
+ title: text.loadFailed,
122
+ description: description,
123
+ action: onRetry ? /*#__PURE__*/ jsx("button", {
124
+ type: "button",
125
+ className: "ov-file-preview__button",
126
+ onClick: onRetry,
127
+ children: text.retry
128
+ }) : void 0
129
+ });
130
+ }
131
+ function UnsupportedState({ text, onDownload }) {
132
+ return /*#__PURE__*/ jsx(StatePanel, {
133
+ title: text.unsupported,
134
+ action: onDownload ? /*#__PURE__*/ jsx("button", {
135
+ type: "button",
136
+ className: "ov-file-preview__button",
137
+ onClick: onDownload,
138
+ children: text.download
139
+ }) : void 0
140
+ });
141
+ }
142
+ function TruncatedNotice({ text }) {
143
+ return /*#__PURE__*/ jsx("p", {
144
+ className: "ov-file-preview__notice",
145
+ children: text.truncated
146
+ });
147
+ }
148
+ const Viewer = /*#__PURE__*/ lazy(async ()=>{
149
+ const { FilePreviewViewer } = await import("./file-preview-viewer~0.js");
150
+ return {
151
+ default: FilePreviewViewer
152
+ };
153
+ });
154
+ function LazyFilePreviewViewer(props) {
155
+ return /*#__PURE__*/ jsx(Suspense, {
156
+ fallback: /*#__PURE__*/ jsx(LoadingState, {
157
+ text: props.text
158
+ }),
159
+ children: /*#__PURE__*/ jsx(Viewer, {
160
+ ...props
161
+ })
162
+ });
163
+ }
164
+ function FilePreviewBody({ fileTab, text, locale, viewMode, editing, onViewModeChange, onHandleChange, onViewModesChange, onDownload, onLinkClick, onCancelEditing }) {
165
+ if (editing.editing || editing.loadingEdit || editing.editFailed) return /*#__PURE__*/ jsx(FilePreviewEditor, {
166
+ draft: editing.draft,
167
+ text: text,
168
+ loading: editing.loadingEdit,
169
+ failed: editing.editFailed,
170
+ saveFailed: editing.saveFailed,
171
+ saving: editing.saving,
172
+ onChange: editing.updateDraft,
173
+ onCancel: onCancelEditing
174
+ });
175
+ if (fileTab.loading) return /*#__PURE__*/ jsx(LoadingState, {
176
+ text: text
177
+ });
178
+ if (isEmptyFile(fileTab.source)) return /*#__PURE__*/ jsx(EmptyFileState, {
179
+ text: text
180
+ });
181
+ return /*#__PURE__*/ jsx(LazyFilePreviewViewer, {
182
+ tab: fileTab,
183
+ text: text,
184
+ locale: locale,
185
+ viewMode: viewMode,
186
+ onViewModeChange: onViewModeChange,
187
+ onDownload: onDownload,
188
+ onHandleChange: onHandleChange,
189
+ onViewModesChange: onViewModesChange,
190
+ onLinkClick: onLinkClick
191
+ });
192
+ }
193
+ const DEFAULT_LABELS = {
194
+ close: 'Close'
195
+ };
196
+ function useMergedRef(ref, target) {
197
+ const merged = useCallback((node)=>{
198
+ target.current = node;
199
+ if ('function' == typeof ref) ref(node);
200
+ else if (ref) ref.current = node;
201
+ }, [
202
+ ref,
203
+ target
204
+ ]);
205
+ return merged;
206
+ }
207
+ function Tooltip({ children, content, placement = 'top', trigger = 'hover', delay = 300, disabled = false, className, style, onOpenChange, labels }) {
208
+ const text = {
209
+ ...DEFAULT_LABELS,
210
+ ...labels
211
+ };
212
+ const [open, setOpen] = useState(false);
213
+ const triggerRef = useRef(null);
214
+ const timerRef = useRef(void 0);
215
+ const [surfaceNode, setSurfaceNode] = useState(null);
216
+ const id = useId();
217
+ const position = useOverlayPosition(open, triggerRef, surfaceNode, placement);
218
+ const change = useCallback((next)=>{
219
+ setOpen(next);
220
+ onOpenChange?.(next);
221
+ }, [
222
+ onOpenChange
223
+ ]);
224
+ const clearTimer = useCallback(()=>{
225
+ if (void 0 !== timerRef.current) {
226
+ window.clearTimeout(timerRef.current);
227
+ timerRef.current = void 0;
228
+ }
229
+ }, []);
230
+ useEffect(()=>clearTimer, [
231
+ clearTimer
232
+ ]);
233
+ useEffect(()=>{
234
+ if (disabled) {
235
+ clearTimer();
236
+ setOpen(false);
237
+ }
238
+ }, [
239
+ disabled,
240
+ clearTimer
241
+ ]);
242
+ useEffect(()=>{
243
+ if (!open || 'click' !== trigger) return;
244
+ const onPointerDown = (event)=>{
245
+ const target = event.target;
246
+ if (surfaceNode?.contains(target) || triggerRef.current?.contains(target)) return;
247
+ change(false);
248
+ };
249
+ const onKeyDown = (event)=>{
250
+ if ('Escape' === event.key) change(false);
251
+ };
252
+ document.addEventListener('mousedown', onPointerDown);
253
+ document.addEventListener('keydown', onKeyDown);
254
+ return ()=>{
255
+ document.removeEventListener('mousedown', onPointerDown);
256
+ document.removeEventListener('keydown', onKeyDown);
257
+ };
258
+ }, [
259
+ change,
260
+ open,
261
+ surfaceNode,
262
+ trigger
263
+ ]);
264
+ const show = ()=>{
265
+ if (disabled) return;
266
+ if ('click' === trigger) return void change(!open);
267
+ clearTimer();
268
+ timerRef.current = window.setTimeout(()=>{
269
+ change(true);
270
+ timerRef.current = void 0;
271
+ }, delay);
272
+ };
273
+ const hide = ()=>{
274
+ if ('click' === trigger) return;
275
+ clearTimer();
276
+ change(false);
277
+ };
278
+ const child = children;
279
+ const childProps = child.props;
280
+ const childRef = child.ref;
281
+ const mergedRef = useMergedRef(childRef, triggerRef);
282
+ const triggerElement = /*#__PURE__*/ cloneElement(child, {
283
+ ref: mergedRef,
284
+ 'aria-describedby': open && 'hover' === trigger ? id : void 0,
285
+ 'aria-expanded': 'click' === trigger ? open : void 0,
286
+ onMouseEnter: (event)=>{
287
+ childProps.onMouseEnter?.(event);
288
+ if ('hover' === trigger) show();
289
+ },
290
+ onMouseLeave: (event)=>{
291
+ childProps.onMouseLeave?.(event);
292
+ if ('hover' === trigger) hide();
293
+ },
294
+ onFocus: (event)=>{
295
+ childProps.onFocus?.(event);
296
+ if ('hover' === trigger) show();
297
+ },
298
+ onBlur: (event)=>{
299
+ childProps.onBlur?.(event);
300
+ hide();
301
+ },
302
+ onClick: (event)=>{
303
+ childProps.onClick?.(event);
304
+ if ('click' === trigger) show();
305
+ }
306
+ });
307
+ const surface = open ? /*#__PURE__*/ createPortal(/*#__PURE__*/ jsx("div", {
308
+ ref: setSurfaceNode,
309
+ id: id,
310
+ role: 'hover' === trigger ? 'tooltip' : 'dialog',
311
+ "aria-label": 'click' === trigger ? text.close : void 0,
312
+ className: [
313
+ 'ov-tooltip',
314
+ className
315
+ ].filter(Boolean).join(' '),
316
+ "data-placement": position.placement,
317
+ style: {
318
+ top: position.top,
319
+ left: position.left,
320
+ ...style
321
+ },
322
+ onMouseEnter: 'hover' === trigger ? clearTimer : void 0,
323
+ onMouseLeave: 'hover' === trigger ? hide : void 0,
324
+ children: content
325
+ }), document.body) : null;
326
+ return /*#__PURE__*/ jsxs(Fragment, {
327
+ children: [
328
+ triggerElement,
329
+ surface
330
+ ]
331
+ });
332
+ }
333
+ function FilePreviewBreadcrumbMenu({ segments, canOpen, disabled, onOpen }) {
334
+ return /*#__PURE__*/ jsx(Tooltip, {
335
+ trigger: "click",
336
+ placement: "bottom",
337
+ className: "ov-file-preview__breadcrumb-menu-surface",
338
+ content: /*#__PURE__*/ jsx("ul", {
339
+ className: "ov-file-preview__breadcrumb-menu",
340
+ role: "menu",
341
+ children: segments.map((segment)=>/*#__PURE__*/ jsx("li", {
342
+ role: "none",
343
+ children: /*#__PURE__*/ jsxs("button", {
344
+ type: "button",
345
+ role: "menuitem",
346
+ disabled: !canOpen || disabled,
347
+ onClick: ()=>onOpen(segment.uri),
348
+ children: [
349
+ segment.label,
350
+ "/"
351
+ ]
352
+ })
353
+ }, segment.uri))
354
+ }),
355
+ children: /*#__PURE__*/ jsx("button", {
356
+ type: "button",
357
+ className: "ov-file-preview__breadcrumb-more",
358
+ "aria-label": "Show hidden path levels",
359
+ "aria-haspopup": "menu",
360
+ children: "…"
361
+ })
362
+ });
363
+ }
364
+ const MAX_ANCESTOR_WIDTH = 160;
365
+ const OVERFLOW_BUTTON_WIDTH = 36;
366
+ const SHIFT_DURATION = 160;
367
+ function prefersReducedMotion() {
368
+ return "u" > typeof window && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
369
+ }
370
+ function measureAvailable(root) {
371
+ const row = root.parentElement;
372
+ if (!row) return root.clientWidth;
373
+ const style = window.getComputedStyle(row);
374
+ const gap = Number.parseFloat(style.columnGap) || 0;
375
+ const siblings = Array.from(row.children).filter((child)=>child !== root && child instanceof HTMLElement);
376
+ const siblingWidth = siblings.reduce((sum, child)=>sum + child.getBoundingClientRect().width, 0);
377
+ const siblingGaps = gap * siblings.length;
378
+ return Math.max(0, row.clientWidth - siblingWidth - siblingGaps);
379
+ }
380
+ function FilePreviewBreadcrumb({ segments, title, canOpen, disabled, onOpen }) {
381
+ const rootRef = useRef(null);
382
+ const measureRef = useRef(null);
383
+ const currentRef = useRef(null);
384
+ const previousRef = useRef(void 0);
385
+ const [hiddenCount, setHiddenCount] = useState(0);
386
+ const [rootHidden, setRootHidden] = useState(false);
387
+ const [overflowing, setOverflowing] = useState(false);
388
+ const signature = JSON.stringify([
389
+ segments.map((s)=>s.uri),
390
+ title
391
+ ]);
392
+ useLayoutEffect(()=>{
393
+ const root = rootRef.current;
394
+ const measure = measureRef.current;
395
+ if (!root || !measure) return;
396
+ const run = ()=>{
397
+ const widths = Array.from(measure.children).map((child)=>child.getBoundingClientRect().width);
398
+ const available = measureAvailable(root);
399
+ const isOverflowing = widths.reduce((sum, width)=>sum + width, 0) > available;
400
+ const capped = isOverflowing ? widths.map((width, index)=>index < widths.length - 1 ? Math.min(width, MAX_ANCESTOR_WIDTH) : width) : widths;
401
+ const ancestors = capped.slice(0, -1);
402
+ const trailing = capped[capped.length - 1] ?? 0;
403
+ const total = capped.reduce((sum, width)=>sum + width, 0);
404
+ setOverflowing(isOverflowing);
405
+ let count = 0;
406
+ let used = total;
407
+ while(used > available && count < ancestors.length - 1){
408
+ used -= ancestors[count + 1] ?? 0;
409
+ if (0 === count) used += OVERFLOW_BUTTON_WIDTH;
410
+ count += 1;
411
+ }
412
+ let hideRoot = false;
413
+ if (used > available && ancestors.length > 0) {
414
+ const rootCollapsed = OVERFLOW_BUTTON_WIDTH + trailing;
415
+ hideRoot = rootCollapsed < used;
416
+ }
417
+ setHiddenCount(hideRoot ? ancestors.length : count);
418
+ setRootHidden(hideRoot);
419
+ };
420
+ run();
421
+ const observer = new ResizeObserver(run);
422
+ observer.observe(root);
423
+ observer.observe(measure);
424
+ if (root.parentElement) observer.observe(root.parentElement);
425
+ return ()=>observer.disconnect();
426
+ }, [
427
+ segments,
428
+ title
429
+ ]);
430
+ useLayoutEffect(()=>{
431
+ const current = currentRef.current;
432
+ const previous = previousRef.current;
433
+ if (!current) return;
434
+ const left = current.offsetLeft;
435
+ previousRef.current = {
436
+ signature,
437
+ left
438
+ };
439
+ if (!previous || previous.signature !== signature || previous.left === left || prefersReducedMotion()) return;
440
+ const animation = current.animate([
441
+ {
442
+ transform: `translateX(${previous.left - left}px)`,
443
+ opacity: 0.65
444
+ },
445
+ {
446
+ transform: 'translateX(0)',
447
+ opacity: 1
448
+ }
449
+ ], {
450
+ duration: SHIFT_DURATION,
451
+ easing: 'cubic-bezier(0.2, 0, 0, 1)'
452
+ });
453
+ return ()=>animation.cancel();
454
+ }, [
455
+ hiddenCount,
456
+ rootHidden,
457
+ signature
458
+ ]);
459
+ const hiddenSegments = segments.filter((_, index)=>rootHidden ? index < hiddenCount : index > 0 && index <= hiddenCount);
460
+ const menu = hiddenSegments.length ? /*#__PURE__*/ jsx(FilePreviewBreadcrumbMenu, {
461
+ segments: hiddenSegments,
462
+ canOpen: canOpen,
463
+ disabled: disabled,
464
+ onOpen: onOpen
465
+ }) : null;
466
+ return /*#__PURE__*/ jsxs("div", {
467
+ className: [
468
+ 'ov-file-preview__breadcrumb',
469
+ overflowing ? 'ov-file-preview__breadcrumb--overflowing' : ''
470
+ ].filter(Boolean).join(' '),
471
+ ref: rootRef,
472
+ children: [
473
+ /*#__PURE__*/ jsxs("div", {
474
+ className: "ov-file-preview__breadcrumb-measure",
475
+ ref: measureRef,
476
+ "aria-hidden": "true",
477
+ children: [
478
+ segments.map((segment)=>/*#__PURE__*/ jsxs("span", {
479
+ className: "ov-file-preview__breadcrumb-part",
480
+ children: [
481
+ /*#__PURE__*/ jsx("span", {
482
+ children: segment.isFirst ? `${segment.uri}` : segment.label
483
+ }),
484
+ /*#__PURE__*/ jsx("span", {
485
+ className: "ov-file-preview__breadcrumb-separator",
486
+ children: "/"
487
+ })
488
+ ]
489
+ }, segment.uri)),
490
+ /*#__PURE__*/ jsx("span", {
491
+ children: title
492
+ })
493
+ ]
494
+ }),
495
+ rootHidden && menu ? /*#__PURE__*/ jsxs("span", {
496
+ className: "ov-file-preview__breadcrumb-part",
497
+ children: [
498
+ menu,
499
+ /*#__PURE__*/ jsx("span", {
500
+ className: "ov-file-preview__breadcrumb-separator",
501
+ children: "/"
502
+ })
503
+ ]
504
+ }) : null,
505
+ segments.map((segment, index)=>{
506
+ if (hiddenSegments.includes(segment)) return null;
507
+ return /*#__PURE__*/ jsxs(external_react_Fragment, {
508
+ children: [
509
+ /*#__PURE__*/ jsxs("span", {
510
+ className: "ov-file-preview__breadcrumb-part",
511
+ children: [
512
+ /*#__PURE__*/ jsx("button", {
513
+ type: "button",
514
+ className: "ov-file-preview__breadcrumb-link",
515
+ disabled: !canOpen || disabled,
516
+ title: segment.uri,
517
+ onClick: ()=>onOpen(segment.uri),
518
+ children: segment.isFirst ? `${segment.uri}` : segment.label
519
+ }),
520
+ /*#__PURE__*/ jsx("span", {
521
+ className: "ov-file-preview__breadcrumb-separator",
522
+ children: "/"
523
+ })
524
+ ]
525
+ }),
526
+ 0 === index && !rootHidden && menu ? /*#__PURE__*/ jsxs("span", {
527
+ className: "ov-file-preview__breadcrumb-part",
528
+ children: [
529
+ menu,
530
+ /*#__PURE__*/ jsx("span", {
531
+ className: "ov-file-preview__breadcrumb-separator",
532
+ children: "/"
533
+ })
534
+ ]
535
+ }) : null
536
+ ]
537
+ }, segment.uri);
538
+ }),
539
+ /*#__PURE__*/ jsx("span", {
540
+ ref: currentRef,
541
+ className: "ov-file-preview__breadcrumb-current",
542
+ "aria-current": "page",
543
+ title: title,
544
+ children: title
545
+ })
546
+ ]
547
+ });
548
+ }
549
+ function FilePreviewCopyPath({ label, disabled, onClick }) {
550
+ return /*#__PURE__*/ jsx(Tooltip, {
551
+ content: label,
552
+ children: /*#__PURE__*/ jsx("button", {
553
+ type: "button",
554
+ className: "ov-file-preview__action",
555
+ "aria-label": label,
556
+ disabled: disabled,
557
+ onClick: onClick,
558
+ children: /*#__PURE__*/ jsx("svg", {
559
+ width: "14",
560
+ height: "14",
561
+ viewBox: "0 0 14 14",
562
+ fill: "none",
563
+ stroke: "currentColor",
564
+ strokeWidth: "1.2",
565
+ strokeLinecap: "round",
566
+ strokeLinejoin: "round",
567
+ "aria-hidden": "true",
568
+ children: /*#__PURE__*/ jsx("path", {
569
+ d: "M4.667 4.667V3.033c0-.653 0-.98.127-1.229a1.167 1.167 0 0 1 .51-.51c.25-.127.576-.127 1.23-.127h4.433c.653 0 .98 0 1.229.127.22.112.398.29.51.51.127.25.127.576.127 1.23v4.433c0 .653 0 .98-.127 1.229a1.167 1.167 0 0 1-.51.51c-.25.127-.576.127-1.23.127H9.333M3.033 12.833h4.434c.653 0 .98 0 1.229-.127.22-.112.398-.29.51-.51.127-.25.127-.576.127-1.229V6.533c0-.653 0-.98-.127-1.229a1.167 1.167 0 0 0-.51-.51c-.25-.127-.576-.127-1.23-.127H3.034c-.653 0-.98 0-1.23.127a1.167 1.167 0 0 0-.51.51c-.126.25-.126.576-.126 1.23v4.433c0 .653 0 .98.127 1.229.112.22.29.398.51.51.25.127.576.127 1.23.127Z"
570
+ })
571
+ })
572
+ })
573
+ });
574
+ }
575
+ const SEPARATOR = '/';
576
+ function splitPathSegments(path) {
577
+ const trimmed = path?.trim();
578
+ if (!trimmed) return [];
579
+ const schemeIndex = trimmed.indexOf('://');
580
+ const scheme = schemeIndex >= 0 ? trimmed.slice(0, schemeIndex + 3) : '';
581
+ const body = schemeIndex >= 0 ? trimmed.slice(schemeIndex + 3) : trimmed;
582
+ const parts = body.split(SEPARATOR).filter(Boolean);
583
+ if (parts.length <= 1) return [];
584
+ const root = '' === scheme && body.startsWith(SEPARATOR) ? SEPARATOR : '';
585
+ const segments = [];
586
+ let uri = scheme;
587
+ parts.slice(0, -1).forEach((part, index)=>{
588
+ uri = 0 === index ? `${scheme}${root}${part}` : `${uri}${SEPARATOR}${part}`;
589
+ segments.push({
590
+ label: part,
591
+ uri,
592
+ isFirst: 0 === index
593
+ });
594
+ });
595
+ return segments;
596
+ }
597
+ function getPathFileName(path) {
598
+ const trimmed = path?.trim();
599
+ if (!trimmed) return;
600
+ const parts = trimmed.split(SEPARATOR).filter(Boolean);
601
+ return parts[parts.length - 1];
602
+ }
603
+ function FilePreviewHeader({ path, fileName, canOpenParent, titleExtra, slotActions, actions, text, onOpenParent }) {
604
+ const segments = splitPathSegments(path);
605
+ const title = getPathFileName(path) ?? fileName;
606
+ const actionNode = 'function' == typeof slotActions ? slotActions(actions) : slotActions;
607
+ return /*#__PURE__*/ jsxs("div", {
608
+ className: "ov-file-preview__header",
609
+ children: [
610
+ /*#__PURE__*/ jsxs("div", {
611
+ className: "ov-file-preview__path-row",
612
+ children: [
613
+ /*#__PURE__*/ jsx(FilePreviewBreadcrumb, {
614
+ segments: segments,
615
+ title: title,
616
+ canOpen: canOpenParent,
617
+ disabled: actions.busy,
618
+ onOpen: onOpenParent
619
+ }),
620
+ actions.canCopyPath ? /*#__PURE__*/ jsx(FilePreviewCopyPath, {
621
+ label: text.copyPath,
622
+ disabled: actions.busy,
623
+ onClick: ()=>void actions.copyPath()
624
+ }) : null,
625
+ titleExtra
626
+ ]
627
+ }),
628
+ actionNode ? /*#__PURE__*/ jsx("div", {
629
+ className: "ov-file-preview__header-actions",
630
+ children: actionNode
631
+ }) : null
632
+ ]
633
+ });
634
+ }
635
+ function levelToFileTab(tab, key) {
636
+ const level = tab.levels.find((candidate)=>candidate.key === key);
637
+ if (!level) return;
638
+ return {
639
+ kind: 'file',
640
+ key: `${tab.key}::${level.key}`,
641
+ source: level.source,
642
+ operations: tab.operations,
643
+ slots: tab.slots
644
+ };
645
+ }
646
+ function FilePreviewDirectoryBody({ tab, text, locale, actions, editing, viewMode, onViewModeChange, onHandleChange, onViewModesChange, onDownload, onCancelEditing }) {
647
+ const [internalKey, setInternalKey] = useState(()=>tab.defaultLevelKey ?? tab.levels[0].key);
648
+ const activeKey = tab.activeLevelKey ?? internalKey;
649
+ const fileTab = levelToFileTab(tab, activeKey) ?? levelToFileTab(tab, tab.levels[0].key);
650
+ const tabsRef = useRef(null);
651
+ const [indicator, setIndicator] = useState({
652
+ left: 0,
653
+ width: 0
654
+ });
655
+ useLayoutEffect(()=>{
656
+ const root = tabsRef.current;
657
+ if (!root) return;
658
+ const measure = ()=>{
659
+ const active = root.querySelector('[aria-selected="true"]');
660
+ if (!active) return;
661
+ setIndicator({
662
+ left: active.offsetLeft,
663
+ width: active.offsetWidth
664
+ });
665
+ };
666
+ measure();
667
+ const observer = new ResizeObserver(measure);
668
+ observer.observe(root);
669
+ return ()=>observer.disconnect();
670
+ }, [
671
+ activeKey,
672
+ tab.levels
673
+ ]);
674
+ const changeLevel = (key)=>{
675
+ if (void 0 === tab.activeLevelKey) setInternalKey(key);
676
+ tab.onActiveLevelChange?.(key);
677
+ };
678
+ const onLevelKeyDown = (event)=>{
679
+ const keys = [
680
+ 'ArrowLeft',
681
+ 'ArrowRight',
682
+ 'Home',
683
+ 'End'
684
+ ];
685
+ if (!keys.includes(event.key)) return;
686
+ const buttons = Array.from(event.currentTarget.querySelectorAll('[role="tab"]:not(:disabled)'));
687
+ if (0 === buttons.length) return;
688
+ const current = buttons.indexOf(event.target);
689
+ const next = 'Home' === event.key ? 0 : 'End' === event.key ? buttons.length - 1 : (current + ('ArrowRight' === event.key ? 1 : -1) + buttons.length) % buttons.length;
690
+ const target = buttons[next];
691
+ if (!target) return;
692
+ event.preventDefault();
693
+ target.focus();
694
+ const key = tab.levels[next]?.key;
695
+ if (void 0 !== key) changeLevel(key);
696
+ };
697
+ if (!fileTab) return null;
698
+ if (tab.loading) return /*#__PURE__*/ jsxs(Fragment, {
699
+ children: [
700
+ /*#__PURE__*/ jsx(FilePreviewHeader, {
701
+ path: fileTab.source.path,
702
+ fileName: fileTab.source.fileName,
703
+ canOpenParent: Boolean(tab.operations?.openParent),
704
+ titleExtra: tab.slots?.titleExtra,
705
+ slotActions: tab.slots?.actions,
706
+ actions: actions,
707
+ text: text,
708
+ onOpenParent: (uri)=>void tab.operations?.openParent?.(uri)
709
+ }),
710
+ /*#__PURE__*/ jsx("div", {
711
+ className: "ov-file-preview__body",
712
+ children: /*#__PURE__*/ jsx(LoadingState, {
713
+ text: text
714
+ })
715
+ })
716
+ ]
717
+ });
718
+ return /*#__PURE__*/ jsxs(Fragment, {
719
+ children: [
720
+ /*#__PURE__*/ jsx(FilePreviewHeader, {
721
+ path: fileTab.source.path,
722
+ fileName: fileTab.source.fileName,
723
+ canOpenParent: Boolean(tab.operations?.openParent),
724
+ titleExtra: tab.slots?.titleExtra,
725
+ slotActions: tab.slots?.actions,
726
+ actions: actions,
727
+ text: text,
728
+ onOpenParent: (uri)=>void tab.operations?.openParent?.(uri)
729
+ }),
730
+ tab.levels.length > 1 ? /*#__PURE__*/ jsxs("div", {
731
+ className: "ov-file-preview__levels",
732
+ role: "tablist",
733
+ ref: tabsRef,
734
+ tabIndex: -1,
735
+ onKeyDown: onLevelKeyDown,
736
+ children: [
737
+ tab.levels.map((level)=>/*#__PURE__*/ jsx("button", {
738
+ type: "button",
739
+ role: "tab",
740
+ "aria-selected": level.key === activeKey,
741
+ tabIndex: level.key === activeKey ? 0 : -1,
742
+ className: "ov-file-preview__level",
743
+ "data-active": level.key === activeKey || void 0,
744
+ onClick: ()=>changeLevel(level.key),
745
+ children: level.label
746
+ }, level.key)),
747
+ /*#__PURE__*/ jsx("span", {
748
+ "aria-hidden": "true",
749
+ className: "ov-file-preview__level-indicator",
750
+ style: {
751
+ transform: `translateX(${indicator.left}px)`,
752
+ width: indicator.width
753
+ }
754
+ })
755
+ ]
756
+ }) : null,
757
+ /*#__PURE__*/ jsx("div", {
758
+ className: "ov-file-preview__body",
759
+ children: /*#__PURE__*/ jsx(FilePreviewBody, {
760
+ fileTab: fileTab,
761
+ text: text,
762
+ locale: locale,
763
+ viewMode: viewMode,
764
+ editing: editing,
765
+ onViewModeChange: onViewModeChange,
766
+ onHandleChange: onHandleChange,
767
+ onViewModesChange: onViewModesChange,
768
+ onDownload: onDownload,
769
+ onCancelEditing: onCancelEditing
770
+ })
771
+ }),
772
+ tab.slots?.footer ? /*#__PURE__*/ jsx("div", {
773
+ className: "ov-file-preview__footer",
774
+ children: tab.slots.footer
775
+ }) : null
776
+ ]
777
+ });
778
+ }
779
+ function FilePreviewPanels({ contentTab, directoryTab, fileTab, panelProps, panelClass, text, locale, actions, actionContext, editing, viewMode, setViewMode, onHandleChange, onViewModesChange, linkClickHandler, activeTab }) {
780
+ if (contentTab) return /*#__PURE__*/ jsx("div", {
781
+ ...panelProps,
782
+ className: `${panelClass} ${panelClass}--content`,
783
+ children: contentTab.content
784
+ });
785
+ if (directoryTab) return /*#__PURE__*/ jsx("div", {
786
+ ...panelProps,
787
+ className: panelClass,
788
+ children: /*#__PURE__*/ jsx(FilePreviewDirectoryBody, {
789
+ tab: directoryTab,
790
+ text: text,
791
+ locale: locale,
792
+ actions: actionContext,
793
+ editing: editing,
794
+ viewMode: viewMode,
795
+ onViewModeChange: setViewMode,
796
+ onHandleChange: onHandleChange,
797
+ onViewModesChange: onViewModesChange,
798
+ onDownload: ()=>{},
799
+ onCancelEditing: actionContext.cancelEditing
800
+ })
801
+ });
802
+ if (!fileTab) return null;
803
+ return /*#__PURE__*/ jsxs("div", {
804
+ ...panelProps,
805
+ className: panelClass,
806
+ children: [
807
+ /*#__PURE__*/ jsx(FilePreviewHeader, {
808
+ path: fileTab.source.path,
809
+ fileName: fileTab.source.fileName,
810
+ canOpenParent: Boolean(fileTab.operations?.openParent),
811
+ titleExtra: fileTab.slots?.titleExtra,
812
+ slotActions: fileTab.slots?.actions,
813
+ actions: actionContext,
814
+ text: text,
815
+ onOpenParent: (uri)=>void actions.openParent(activeTab, uri)
816
+ }),
817
+ /*#__PURE__*/ jsx("div", {
818
+ className: "ov-file-preview__body",
819
+ children: /*#__PURE__*/ jsx(FilePreviewBody, {
820
+ fileTab: fileTab,
821
+ text: text,
822
+ locale: locale,
823
+ viewMode: viewMode,
824
+ editing: editing,
825
+ onViewModeChange: setViewMode,
826
+ onHandleChange: onHandleChange,
827
+ onViewModesChange: onViewModesChange,
828
+ onDownload: ()=>void actions.download(fileTab),
829
+ onLinkClick: linkClickHandler,
830
+ onCancelEditing: actionContext.cancelEditing
831
+ })
832
+ }),
833
+ fileTab.source.truncated ? /*#__PURE__*/ jsx(TruncatedNotice, {
834
+ text: text
835
+ }) : null,
836
+ fileTab.slots?.footer ? /*#__PURE__*/ jsx("div", {
837
+ className: "ov-file-preview__footer",
838
+ children: fileTab.slots.footer
839
+ }) : null
840
+ ]
841
+ });
842
+ }
843
+ const file_preview_labels_DEFAULT_LABELS = {
844
+ copyPath: 'Copy path',
845
+ editor: 'Edit content',
846
+ leaveEditing: 'Cancel',
847
+ retry: 'Retry',
848
+ loadFailed: 'Failed to load the file',
849
+ saveFailed: 'Failed to save',
850
+ unsupported: 'Preview is not supported for this format',
851
+ loading: 'Loading…',
852
+ download: 'Download',
853
+ fileEmpty: 'This file is empty',
854
+ noContent: 'No content to show',
855
+ truncated: 'Only part of the content is shown'
856
+ };
857
+ const OUTLINE_RADIUS = 7;
858
+ const STROKE_INSET = 0.5;
859
+ function buildOutline(width, top, bottom, left, right) {
860
+ const radius = OUTLINE_RADIUS;
861
+ if (right - left < 2 * radius + 1) return `M0 ${bottom} H${width}`;
862
+ const lead = left > radius ? [
863
+ `M0 ${bottom}`,
864
+ `H${left - radius}`
865
+ ] : [
866
+ `M${left} ${bottom}`
867
+ ];
868
+ return [
869
+ ...lead,
870
+ `Q${left} ${bottom} ${left} ${bottom - radius}`,
871
+ `V${top + radius}`,
872
+ `Q${left} ${top} ${left + radius} ${top}`,
873
+ `H${right - radius}`,
874
+ `Q${right} ${top} ${right} ${top + radius}`,
875
+ `V${bottom - radius}`,
876
+ `Q${right} ${bottom} ${right + radius} ${bottom}`,
877
+ `H${width}`
878
+ ].join(' ');
879
+ }
880
+ function FilePreviewTabRow({ tabs, activeKey, disabled, tabId, panelId, onSelect }) {
881
+ const trackRef = useRef(null);
882
+ const [outline, setOutline] = useState('');
883
+ useLayoutEffect(()=>{
884
+ const track = trackRef.current;
885
+ if (!track) return;
886
+ const measure = ()=>{
887
+ const trackRect = track.getBoundingClientRect();
888
+ const bottom = trackRect.height - STROKE_INSET;
889
+ const active = track.querySelector('[aria-selected="true"]');
890
+ if (!active) return void setOutline(`M0 ${bottom} H${trackRect.width}`);
891
+ const rect = active.getBoundingClientRect();
892
+ setOutline(buildOutline(trackRect.width, rect.top - trackRect.top + STROKE_INSET, rect.bottom - trackRect.top - STROKE_INSET, rect.left - trackRect.left, rect.right - trackRect.left));
893
+ };
894
+ measure();
895
+ const observer = new ResizeObserver(measure);
896
+ observer.observe(track);
897
+ return ()=>observer.disconnect();
898
+ }, [
899
+ activeKey,
900
+ tabs
901
+ ]);
902
+ const onKeyDown = (event)=>{
903
+ const keys = [
904
+ 'ArrowLeft',
905
+ 'ArrowRight',
906
+ 'Home',
907
+ 'End'
908
+ ];
909
+ if (!keys.includes(event.key)) return;
910
+ const buttons = Array.from(event.currentTarget.querySelectorAll('[role="tab"]:not(:disabled)'));
911
+ if (0 === buttons.length) return;
912
+ const current = buttons.indexOf(event.target);
913
+ const next = 'Home' === event.key ? 0 : 'End' === event.key ? buttons.length - 1 : (current + ('ArrowRight' === event.key ? 1 : -1) + buttons.length) % buttons.length;
914
+ const target = buttons[next];
915
+ if (!target) return;
916
+ event.preventDefault();
917
+ target.focus();
918
+ onSelect(target.dataset.key ?? '');
919
+ };
920
+ return /*#__PURE__*/ jsx("div", {
921
+ className: "ov-file-preview__tab-row",
922
+ children: /*#__PURE__*/ jsxs("div", {
923
+ role: "tablist",
924
+ className: "ov-file-preview__tab-track",
925
+ ref: trackRef,
926
+ tabIndex: -1,
927
+ onKeyDown: onKeyDown,
928
+ children: [
929
+ tabs.map((tab)=>{
930
+ const selected = tab.key === activeKey;
931
+ return /*#__PURE__*/ jsxs("button", {
932
+ type: "button",
933
+ role: "tab",
934
+ "data-key": tab.key,
935
+ id: tabId(tab.key),
936
+ "aria-selected": selected,
937
+ "aria-controls": panelId(tab.key),
938
+ tabIndex: selected ? 0 : -1,
939
+ disabled: tab.disabled || disabled,
940
+ title: 'string' == typeof tab.title ? tab.title : void 0,
941
+ className: [
942
+ 'ov-file-preview__tab',
943
+ selected ? 'ov-file-preview__tab--active' : ''
944
+ ].filter(Boolean).join(' '),
945
+ onClick: ()=>onSelect(tab.key),
946
+ children: [
947
+ tab.icon ? /*#__PURE__*/ jsx("span", {
948
+ className: "ov-file-preview__tab-icon",
949
+ "aria-hidden": "true",
950
+ children: tab.icon
951
+ }) : null,
952
+ /*#__PURE__*/ jsx("span", {
953
+ className: "ov-file-preview__tab-title",
954
+ children: tab.title ?? ('file' === tab.kind ? tab.source.fileName : tab.key)
955
+ })
956
+ ]
957
+ }, tab.key);
958
+ }),
959
+ /*#__PURE__*/ jsx("svg", {
960
+ className: "ov-file-preview__tab-outline",
961
+ "aria-hidden": "true",
962
+ children: /*#__PURE__*/ jsx("path", {
963
+ d: outline
964
+ })
965
+ })
966
+ ]
967
+ })
968
+ });
969
+ }
970
+ async function copyText(value, notify) {
971
+ try {
972
+ await navigator.clipboard.writeText(value);
973
+ } catch {
974
+ return false;
975
+ }
976
+ notify?.(value);
977
+ return true;
978
+ }
979
+ function useFilePreviewActions() {
980
+ const pending = useRef(new Set());
981
+ async function run(key, { execute, notify }, value) {
982
+ if (!execute || pending.current.has(key)) return;
983
+ pending.current.add(key);
984
+ try {
985
+ await execute(value);
986
+ } catch {
987
+ return;
988
+ } finally{
989
+ pending.current.delete(key);
990
+ }
991
+ notify?.(value);
992
+ }
993
+ return {
994
+ openParent: (tab, uri)=>'content' === tab.kind ? Promise.resolve() : run(`openParent:${tab.key}`, {
995
+ execute: tab.operations?.openParent,
996
+ notify: tab.onOpenParent
997
+ }, uri),
998
+ download: (tab)=>run(`download:${tab.key}`, {
999
+ execute: tab.operations?.download,
1000
+ notify: tab.onDownload
1001
+ }, void 0),
1002
+ openUri: (tab, uri)=>run(`openUri:${tab.key}`, {
1003
+ execute: tab.operations?.openUri,
1004
+ notify: tab.onOpenUri
1005
+ }, uri),
1006
+ copyPath: (tab, path)=>copyText(path, tab.onCopyPath),
1007
+ copyContent: (tab, text)=>copyText(text, 'onCopyContent' in tab ? tab.onCopyContent : void 0)
1008
+ };
1009
+ }
1010
+ function useFilePreviewActionsContext({ activeTab, fileTab, currentPath, currentSource, viewMode, canSwitchView, setViewMode, editing, operations }) {
1011
+ const startEditing = useCallback(()=>{
1012
+ if (!fileTab) return;
1013
+ setViewMode('source');
1014
+ editing.start(fileTab);
1015
+ }, [
1016
+ editing,
1017
+ fileTab,
1018
+ setViewMode
1019
+ ]);
1020
+ const saveEditing = useCallback(async ()=>{
1021
+ if (!fileTab) return false;
1022
+ const saved = await editing.save(fileTab);
1023
+ if (saved) setViewMode('preview');
1024
+ return saved;
1025
+ }, [
1026
+ editing,
1027
+ fileTab,
1028
+ setViewMode
1029
+ ]);
1030
+ const cancelEditing = useCallback(()=>{
1031
+ editing.discard(activeTab);
1032
+ setViewMode('preview');
1033
+ }, [
1034
+ activeTab,
1035
+ editing,
1036
+ setViewMode
1037
+ ]);
1038
+ const copyable = currentSource ? readCopyableText(currentSource) : void 0;
1039
+ const copyContent = useCallback(async ()=>{
1040
+ if (!copyable) return false;
1041
+ return operations.copyContent(activeTab, copyable);
1042
+ }, [
1043
+ activeTab,
1044
+ copyable,
1045
+ operations
1046
+ ]);
1047
+ const copyPath = useCallback(async ()=>{
1048
+ const path = currentPath;
1049
+ if (!path) return false;
1050
+ return operations.copyPath(activeTab, path);
1051
+ }, [
1052
+ activeTab,
1053
+ currentPath,
1054
+ operations
1055
+ ]);
1056
+ const download = useCallback(()=>{
1057
+ if (fileTab) operations.download(fileTab);
1058
+ }, [
1059
+ fileTab,
1060
+ operations
1061
+ ]);
1062
+ return {
1063
+ viewMode,
1064
+ setViewMode,
1065
+ canSwitchView,
1066
+ editing: editing.editing,
1067
+ busy: editing.saving || editing.loadingEdit,
1068
+ canEdit: Boolean(fileTab?.editing) && !editing.editing,
1069
+ startEditing,
1070
+ saveEditing,
1071
+ cancelEditing,
1072
+ canCopyContent: Boolean(copyable),
1073
+ copyContent,
1074
+ canCopyPath: Boolean(currentPath),
1075
+ copyPath,
1076
+ canDownload: Boolean(fileTab?.operations?.download),
1077
+ download
1078
+ };
1079
+ }
1080
+ function useFilePreviewIds(activeKey) {
1081
+ const instanceId = useId();
1082
+ const tabId = (key)=>`${instanceId}-tab-${key}`;
1083
+ const panelId = (key)=>`${instanceId}-panel-${key}`;
1084
+ return {
1085
+ tabId,
1086
+ panelId,
1087
+ panelProps: {
1088
+ id: panelId(activeKey),
1089
+ role: 'tabpanel',
1090
+ 'aria-labelledby': tabId(activeKey)
1091
+ }
1092
+ };
1093
+ }
1094
+ function initialLevelKey(tab, remembered, tabKey) {
1095
+ const preferred = tab.activeLevelKey ?? remembered[tabKey] ?? tab.defaultLevelKey;
1096
+ const first = tab.levels[0]?.key ?? '';
1097
+ if (void 0 === preferred) return first;
1098
+ return tab.levels.some((level)=>level.key === preferred) ? preferred : first;
1099
+ }
1100
+ function useDirectoryLevel(tab) {
1101
+ const [levelKeys, setLevelKeys] = useState({});
1102
+ if (!tab) return {};
1103
+ const activeLevel = tab.levels.find((level)=>level.key === initialLevelKey(tab, levelKeys, tab.key)) ?? tab.levels[0];
1104
+ return {
1105
+ activeLevel,
1106
+ directoryTab: {
1107
+ ...tab,
1108
+ activeLevelKey: activeLevel.key,
1109
+ onActiveLevelChange: (key)=>{
1110
+ if (void 0 === tab.activeLevelKey) setLevelKeys((previous)=>({
1111
+ ...previous,
1112
+ [tab.key]: key
1113
+ }));
1114
+ tab.onActiveLevelChange?.(key);
1115
+ }
1116
+ },
1117
+ source: activeLevel.source
1118
+ };
1119
+ }
1120
+ function useFilePreviewEditing(activeTabKey) {
1121
+ const [editing, setEditing] = useState(false);
1122
+ const [loadingEdit, setLoadingEdit] = useState(false);
1123
+ const [editFailed, setEditFailed] = useState(false);
1124
+ const [saving, setSaving] = useState(false);
1125
+ const [saveFailed, setSaveFailed] = useState(false);
1126
+ const [draft, setDraft] = useState('');
1127
+ const requestId = useRef(0);
1128
+ const loading = useRef(false);
1129
+ const pendingSave = useRef(false);
1130
+ const lastKey = useRef(activeTabKey);
1131
+ if (lastKey.current !== activeTabKey) {
1132
+ lastKey.current = activeTabKey;
1133
+ requestId.current += 1;
1134
+ loading.current = false;
1135
+ if (editing) setEditing(false);
1136
+ if (loadingEdit) setLoadingEdit(false);
1137
+ if (editFailed) setEditFailed(false);
1138
+ if (saveFailed) setSaveFailed(false);
1139
+ if (draft) setDraft('');
1140
+ }
1141
+ function discard(tab) {
1142
+ requestId.current += 1;
1143
+ loading.current = false;
1144
+ const wasEditing = editing;
1145
+ const discarded = draft;
1146
+ setEditing(false);
1147
+ setLoadingEdit(false);
1148
+ setEditFailed(false);
1149
+ setSaveFailed(false);
1150
+ setDraft('');
1151
+ if (wasEditing && 'file' === tab.kind) tab.editing?.onCancel?.(discarded);
1152
+ }
1153
+ async function start(tab) {
1154
+ if (loading.current || pendingSave.current) return;
1155
+ const id = ++requestId.current;
1156
+ loading.current = true;
1157
+ setLoadingEdit(true);
1158
+ setEditFailed(false);
1159
+ setSaveFailed(false);
1160
+ let content;
1161
+ try {
1162
+ content = tab.editing?.loadContent ? await tab.editing.loadContent(tab.source) : tab.source.content ?? await tab.source.file?.text();
1163
+ } catch {
1164
+ if (id === requestId.current) setEditFailed(true);
1165
+ }
1166
+ if (id !== requestId.current) return;
1167
+ loading.current = false;
1168
+ setLoadingEdit(false);
1169
+ if (void 0 !== content) {
1170
+ setDraft(content);
1171
+ setEditing(true);
1172
+ }
1173
+ }
1174
+ async function save(tab) {
1175
+ if (!editing || !tab.editing || pendingSave.current) return false;
1176
+ pendingSave.current = true;
1177
+ setSaving(true);
1178
+ setSaveFailed(false);
1179
+ const value = draft;
1180
+ try {
1181
+ await tab.editing.save(value);
1182
+ } catch {
1183
+ setSaveFailed(true);
1184
+ return false;
1185
+ } finally{
1186
+ pendingSave.current = false;
1187
+ setSaving(false);
1188
+ }
1189
+ setEditing(false);
1190
+ setDraft('');
1191
+ tab.editing.onSave?.(value);
1192
+ return true;
1193
+ }
1194
+ return {
1195
+ editing,
1196
+ loadingEdit,
1197
+ editFailed,
1198
+ saving,
1199
+ saveFailed,
1200
+ draft,
1201
+ discard,
1202
+ start,
1203
+ save,
1204
+ updateDraft: (value)=>{
1205
+ setDraft(value);
1206
+ setSaveFailed(false);
1207
+ }
1208
+ };
1209
+ }
1210
+ function isFileTab(tab) {
1211
+ return 'file' === tab.kind;
1212
+ }
1213
+ const file_preview_FilePreview = /*#__PURE__*/ forwardRef(function({ tabs, activeKey, defaultActiveKey, locale, labels, onActiveKeyChange, className, ...rest }, ref) {
1214
+ const text = {
1215
+ ...file_preview_labels_DEFAULT_LABELS,
1216
+ ...labels
1217
+ };
1218
+ const [internalKey, setInternalKey] = useState(()=>defaultActiveKey ?? tabs[0].key);
1219
+ const [viewMode, setViewMode] = useState('preview');
1220
+ const [viewModes, setViewModes] = useState([]);
1221
+ const viewerHandle = useRef(null);
1222
+ const panelClass = 'ov-file-preview__panel';
1223
+ const currentKey = activeKey ?? internalKey;
1224
+ const activeTab = tabs.find((tab)=>tab.key === currentKey) ?? tabs[0];
1225
+ const { tabId, panelId, panelProps } = useFilePreviewIds(activeTab.key);
1226
+ const editing = useFilePreviewEditing(activeTab.key);
1227
+ const actions = useFilePreviewActions();
1228
+ const tabText = {
1229
+ ...text,
1230
+ ...activeTab.labels
1231
+ };
1232
+ const fileTab = isFileTab(activeTab) ? activeTab : void 0;
1233
+ const directoryTab = 'directory' === activeTab.kind ? activeTab : void 0;
1234
+ const contentTab = fileTab || directoryTab ? void 0 : activeTab;
1235
+ const switchTab = useCallback((key)=>{
1236
+ if (editing.saving) return false;
1237
+ if (key === currentKey && key === activeTab.key) return false;
1238
+ const target = tabs.find((tab)=>tab.key === key);
1239
+ if (!target || target.disabled) return false;
1240
+ const syncingOnly = target.key === activeTab.key;
1241
+ if (!syncingOnly) {
1242
+ editing.discard(activeTab);
1243
+ setViewMode('preview');
1244
+ setViewModes([]);
1245
+ viewerHandle.current = null;
1246
+ }
1247
+ if (void 0 === activeKey) setInternalKey(key);
1248
+ onActiveKeyChange?.(key);
1249
+ return true;
1250
+ }, [
1251
+ activeKey,
1252
+ activeTab,
1253
+ currentKey,
1254
+ editing,
1255
+ onActiveKeyChange,
1256
+ tabs
1257
+ ]);
1258
+ const onHandleChange = useCallback((handle)=>{
1259
+ viewerHandle.current = handle;
1260
+ }, []);
1261
+ const onViewModesChange = useCallback((modes)=>{
1262
+ const next = modes.map((mode)=>mode.value);
1263
+ setViewModes((previous)=>previous.join() === next.join() ? previous : next);
1264
+ }, []);
1265
+ useImperativeHandle(ref, ()=>({
1266
+ setActiveTab: switchTab,
1267
+ getActiveTab: ()=>activeTab.key,
1268
+ getViewerHandle: ()=>fileTab ? viewerHandle.current : null
1269
+ }), [
1270
+ activeTab.key,
1271
+ fileTab,
1272
+ switchTab
1273
+ ]);
1274
+ const canSwitchView = Boolean(fileTab) && viewModes.includes('preview') && viewModes.includes('source');
1275
+ const onLinkClick = useCallback((_event, link)=>{
1276
+ if (fileTab) actions.openUri(fileTab, link.url);
1277
+ }, [
1278
+ actions,
1279
+ fileTab
1280
+ ]);
1281
+ const linkClickHandler = fileTab?.operations?.openUri ? onLinkClick : void 0;
1282
+ const level = useDirectoryLevel(directoryTab);
1283
+ const currentPath = level.source?.path ?? fileTab?.source.path;
1284
+ const currentSource = level.source ?? fileTab?.source;
1285
+ const actionContext = useFilePreviewActionsContext({
1286
+ activeTab,
1287
+ fileTab,
1288
+ currentPath,
1289
+ currentSource,
1290
+ viewMode,
1291
+ canSwitchView,
1292
+ setViewMode,
1293
+ editing,
1294
+ operations: actions
1295
+ });
1296
+ return /*#__PURE__*/ jsxs("div", {
1297
+ ...rest,
1298
+ className: [
1299
+ 'ov-file-preview',
1300
+ className
1301
+ ].filter(Boolean).join(' '),
1302
+ children: [
1303
+ /*#__PURE__*/ jsx(FilePreviewTabRow, {
1304
+ tabs: tabs,
1305
+ activeKey: activeTab.key,
1306
+ disabled: editing.saving,
1307
+ tabId: tabId,
1308
+ panelId: panelId,
1309
+ onSelect: (key)=>void switchTab(key)
1310
+ }),
1311
+ /*#__PURE__*/ jsx(FilePreviewPanels, {
1312
+ contentTab: contentTab,
1313
+ directoryTab: level.directoryTab,
1314
+ fileTab: fileTab,
1315
+ panelProps: panelProps,
1316
+ panelClass: panelClass,
1317
+ text: tabText,
1318
+ locale: locale,
1319
+ actions: actions,
1320
+ actionContext: actionContext,
1321
+ editing: editing,
1322
+ viewMode: viewMode,
1323
+ setViewMode: setViewMode,
1324
+ onHandleChange: onHandleChange,
1325
+ onViewModesChange: onViewModesChange,
1326
+ linkClickHandler: linkClickHandler,
1327
+ activeTab: activeTab
1328
+ })
1329
+ ]
1330
+ });
1331
+ });
1332
+ export { LoadFailedState, LoadingState, Tooltip, UnsupportedState, file_preview_FilePreview as FilePreview, toFileSource };