@openviking/react 0.0.0-stage → 0.1.1

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 (104) hide show
  1. package/README.md +82 -2
  2. package/dist/3~0.js +8 -0
  3. package/dist/a~0.js +21 -0
  4. package/dist/client/client.d.ts +12 -0
  5. package/dist/client/errors.d.ts +30 -0
  6. package/dist/client/index.d.ts +4 -0
  7. package/dist/client/options.d.ts +101 -0
  8. package/dist/client/provider.d.ts +52 -0
  9. package/dist/client/types.d.ts +160 -0
  10. package/dist/client.js +239 -0
  11. package/dist/components/agent-connect/agent-connect.d.ts +4 -0
  12. package/dist/components/agent-connect/index.d.ts +1 -0
  13. package/dist/components/agent-connect/style.css +16 -0
  14. package/dist/components/agent-connect/style.js +0 -0
  15. package/dist/components/agent-connect/types.d.ts +175 -0
  16. package/dist/components/agent-connect.js +1 -0
  17. package/dist/components/file-preview/file-preview-body.d.ts +15 -0
  18. package/dist/components/file-preview/file-preview-header.d.ts +16 -0
  19. package/dist/components/file-preview/file-preview-icons.d.ts +2 -0
  20. package/dist/components/file-preview/file-preview-labels.d.ts +5 -0
  21. package/dist/components/file-preview/file-preview-operations.d.ts +1 -0
  22. package/dist/components/file-preview/file-preview.d.ts +17 -0
  23. package/dist/components/file-preview/index.d.ts +1 -0
  24. package/dist/components/file-preview/style.css +285 -0
  25. package/dist/components/file-preview/style.js +0 -0
  26. package/dist/components/file-preview/types.d.ts +435 -0
  27. package/dist/components/file-preview/use-file-preview-editing.d.ts +13 -0
  28. package/dist/components/file-preview.js +442 -0
  29. package/dist/components/file-tree/file-tree-body.d.ts +14 -0
  30. package/dist/components/file-tree/file-tree-dom.d.ts +4 -0
  31. package/dist/components/file-tree/file-tree-entry-row.d.ts +6 -0
  32. package/dist/components/file-tree/file-tree-icons.d.ts +8 -0
  33. package/dist/components/file-tree/file-tree-keyboard.d.ts +10 -0
  34. package/dist/components/file-tree/file-tree-labels.d.ts +5 -0
  35. package/dist/components/file-tree/file-tree-row-context.d.ts +24 -0
  36. package/dist/components/file-tree/file-tree-rows.d.ts +12 -0
  37. package/dist/components/file-tree/file-tree-tooltip.d.ts +11 -0
  38. package/dist/components/file-tree/file-tree.d.ts +4 -0
  39. package/dist/components/file-tree/index.d.ts +1 -0
  40. package/dist/components/file-tree/style.css +244 -0
  41. package/dist/components/file-tree/style.js +0 -0
  42. package/dist/components/file-tree/types.d.ts +406 -0
  43. package/dist/components/file-tree/use-file-tree-actions.d.ts +10 -0
  44. package/dist/components/file-tree.js +1 -0
  45. package/dist/components/scope-switcher/index.d.ts +1 -0
  46. package/dist/components/scope-switcher/scope-keyboard.d.ts +2 -0
  47. package/dist/components/scope-switcher/scope-panel.d.ts +5 -0
  48. package/dist/components/scope-switcher/scope-selector.d.ts +2 -0
  49. package/dist/components/scope-switcher/scope-switcher.d.ts +6 -0
  50. package/dist/components/scope-switcher/style.css +248 -0
  51. package/dist/components/scope-switcher/style.js +0 -0
  52. package/dist/components/scope-switcher/types.d.ts +367 -0
  53. package/dist/components/scope-switcher.js +3 -0
  54. package/dist/components/style.css +811 -0
  55. package/dist/components/style.js +0 -0
  56. package/dist/components/tui/index.d.ts +1 -0
  57. package/dist/components/tui/style.css +16 -0
  58. package/dist/components/tui/style.js +0 -0
  59. package/dist/components/tui/tui.d.ts +3 -0
  60. package/dist/components/tui/types.d.ts +485 -0
  61. package/dist/components/tui.js +1 -0
  62. package/dist/f~0.js +284 -0
  63. package/dist/icons/index.d.ts +23 -0
  64. package/dist/icons.js +25 -0
  65. package/dist/index.d.ts +16 -0
  66. package/dist/index.js +8 -0
  67. package/dist/i~0.js +21 -0
  68. package/dist/lk~0.js +220 -0
  69. package/dist/l~0.js +44 -0
  70. package/dist/modules/console/console.d.ts +4 -0
  71. package/dist/modules/console/index.d.ts +1 -0
  72. package/dist/modules/console/style.css +29 -0
  73. package/dist/modules/console/style.js +0 -0
  74. package/dist/modules/console/types.d.ts +101 -0
  75. package/dist/modules/console.js +1 -0
  76. package/dist/modules/file-browser/file-browser-toolbar-button.d.ts +10 -0
  77. package/dist/modules/file-browser/file-browser.d.ts +6 -0
  78. package/dist/modules/file-browser/index.d.ts +1 -0
  79. package/dist/modules/file-browser/style.css +75 -0
  80. package/dist/modules/file-browser/style.js +0 -0
  81. package/dist/modules/file-browser/types.d.ts +101 -0
  82. package/dist/modules/file-browser.js +1 -0
  83. package/dist/modules/scope-cascade/controller.d.ts +6 -0
  84. package/dist/modules/scope-cascade/index.d.ts +3 -0
  85. package/dist/modules/scope-cascade/scope-cascade.d.ts +3 -0
  86. package/dist/modules/scope-cascade/style.css +250 -0
  87. package/dist/modules/scope-cascade/style.js +0 -0
  88. package/dist/modules/scope-cascade/types.d.ts +39 -0
  89. package/dist/modules/scope-cascade/use-scope-cascade.d.ts +5 -0
  90. package/dist/modules/scope-cascade.js +1 -0
  91. package/dist/modules/style.css +385 -0
  92. package/dist/modules/style.js +0 -0
  93. package/dist/modules/task-center/columns.d.ts +129 -0
  94. package/dist/modules/task-center/index.d.ts +1 -0
  95. package/dist/modules/task-center/style.css +29 -0
  96. package/dist/modules/task-center/style.js +0 -0
  97. package/dist/modules/task-center/task-center.d.ts +4 -0
  98. package/dist/modules/task-center/types.d.ts +168 -0
  99. package/dist/modules/task-center.js +1 -0
  100. package/dist/n~0.js +499 -0
  101. package/dist/style.css +1198 -0
  102. package/dist/style.js +0 -0
  103. package/dist/u~0.js +8 -0
  104. package/package.json +103 -4
@@ -0,0 +1,168 @@
1
+ import type { OvRequestOptions } from '../../client/index.js';
2
+ import type { HTMLAttributes, ReactNode } from 'react';
3
+ import type { TaskCenterColumns, TaskCenterCompileRow, TaskCenterCompileSchedule, TaskCenterImportRow } from './columns.js';
4
+ /**
5
+ * 任务管理的页签。数据源导入对应定时同步的 watch,知识编译对应编译目标。
6
+ * Tabs of the task center. Data-source import covers scheduled watches; knowledge
7
+ * compile covers compile targets.
8
+ */
9
+ export type TaskCenterTab = 'import' | 'compile';
10
+ /**
11
+ * 页签的可见范围。「其他成员」只在能查看账号下全部任务时出现,由模块从当前
12
+ * 身份判断,不需要宿主传开关。
13
+ *
14
+ * Visibility scope of a tab. "Others" appears only when the current identity can
15
+ * see every task in the account; the module decides that from the current
16
+ * identity, so the host passes no switch.
17
+ */
18
+ export type TaskCenterScope = 'mine' | 'others';
19
+ /** 任务中心模块的插槽。Slots of the task center module. */
20
+ export interface TaskCenterSlots {
21
+ /**
22
+ * 列表上方的工具栏,例如新建任务、搜索。筛选在表头由模块提供。
23
+ * Toolbar above the list, for example a create action or search. The module
24
+ * provides filtering in the table header.
25
+ */
26
+ toolbar?: ReactNode;
27
+ /**
28
+ * 空态内容,例如引导导入资源的入口。
29
+ * Empty state, for example an entry that starts importing resources.
30
+ */
31
+ emptyState?: ReactNode;
32
+ }
33
+ /** 任务中心模块的可替换文案。Replaceable copy of the task center module. */
34
+ export interface TaskCenterLabels {
35
+ /**
36
+ * 占位说明。缺省为 `Placeholder. Functionality is not available yet.`。
37
+ * Placeholder description. Defaults to "Placeholder. Functionality is not
38
+ * available yet.".
39
+ */
40
+ description?: string;
41
+ /** 区域标题。Area title. */
42
+ title?: string;
43
+ /** 数据源导入页签名称。Label of the import tab. */
44
+ importTab?: string;
45
+ /** 知识编译页签名称。Label of the compile tab. */
46
+ compileTab?: string;
47
+ /** 「我的任务」范围名称。Label of the "my tasks" scope. */
48
+ mineScope?: string;
49
+ /** 「其他成员任务」范围名称。Label of the "others' tasks" scope. */
50
+ othersScope?: string;
51
+ /** 没有任务时的提示。Message shown when there are no tasks. */
52
+ empty?: string;
53
+ /** 加载失败提示。Load failure message. */
54
+ error?: string;
55
+ /** 重试按钮文案。Retry button label. */
56
+ retry?: string;
57
+ /** 定时同步列的表头。Header of the scheduled-sync column. */
58
+ scheduleColumn?: string;
59
+ /** 定时同步开启状态文案。Copy for an enabled schedule. */
60
+ scheduleEnabled?: string;
61
+ /** 定时同步关闭状态文案。Copy for a disabled schedule. */
62
+ scheduleDisabled?: string;
63
+ /** 编辑定时周期的按钮文案。Label of the control that edits a schedule. */
64
+ editSchedule?: string;
65
+ /** 定时保存失败时的提示。Message shown when saving a schedule fails. */
66
+ saveFailed?: string;
67
+ }
68
+ /**
69
+ * 任务中心模块的属性。
70
+ *
71
+ * 模块自己通过 Hook 取数,props 里没有任务数据:宿主给配置、受控状态、回调、
72
+ * 列配置、插槽与文案。两个页签各有自己的数据源与列,页签内筛选由模块维护。
73
+ *
74
+ * 能查看「其他成员任务」取决于当前身份,模块自行判断,宿主不需要传权限开关。
75
+ *
76
+ * Props of the task center module.
77
+ *
78
+ * The module loads its own data through a Hook, so no prop carries tasks: the
79
+ * host supplies configuration, controlled state, callbacks, column
80
+ * configuration, slots and copy. Each tab has its own data source and columns,
81
+ * and the module maintains filtering inside a tab.
82
+ *
83
+ * Whether "others' tasks" is available depends on the current identity; the
84
+ * module decides that itself, so the host passes no permission switch.
85
+ */
86
+ export interface TaskCenterProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'children'> {
87
+ /**
88
+ * 受控的当前页签。传入时由宿主决定页签,模块只上报切换意图。
89
+ * The controlled tab. When given, the host owns the tab and the module only
90
+ * reports switch intent.
91
+ */
92
+ tab?: TaskCenterTab;
93
+ /**
94
+ * 非受控时的初始页签,缺省为 `import`。
95
+ * Initial tab when uncontrolled; defaults to `import`.
96
+ */
97
+ defaultTab?: TaskCenterTab;
98
+ /**
99
+ * 受控的页签可见范围。传入时由宿主决定范围,模块只上报切换意图。
100
+ * The controlled scope. When given, the host owns it and the module only
101
+ * reports switch intent.
102
+ */
103
+ scope?: TaskCenterScope;
104
+ /**
105
+ * 非受控时的初始范围,缺省为 `mine`。
106
+ * Initial scope when uncontrolled; defaults to `mine`.
107
+ */
108
+ defaultScope?: TaskCenterScope;
109
+ /**
110
+ * 列配置。省略时两个页签都用各自的内置列与默认顺序。
111
+ * Column configuration. Omission uses each tab's built-in columns in their
112
+ * default order.
113
+ */
114
+ columns?: TaskCenterColumns;
115
+ /**
116
+ * 页签变化后触发。
117
+ * Called after the tab changes.
118
+ */
119
+ onTabChange?: (tab: TaskCenterTab) => void;
120
+ /**
121
+ * 可见范围变化后触发。
122
+ * Called after the scope changes.
123
+ */
124
+ onScopeChange?: (scope: TaskCenterScope) => void;
125
+ /**
126
+ * 打开资源时触发,例如点击导入任务的目标路径。任务详情由模块内部以抽屉展示,
127
+ * 不需要宿主参与。
128
+ * Called when a resource is opened, for example the target path of an import
129
+ * task. Task details are shown by the module in a drawer, so the host takes no
130
+ * part in that.
131
+ */
132
+ onOpenResource?: (uri: string) => void;
133
+ /**
134
+ * 导入任务的同步间隔保存。返回的 Promise 成功即视为已写入,模块随后重新取数;
135
+ * 失败时保留编辑内容并展示错误,错误文案取 `labels.saveFailed`。
136
+ *
137
+ * Saving the sync interval of an import task. A resolved Promise means the
138
+ * write succeeded and the module reloads; a rejection keeps the edit and shows
139
+ * the error from `labels.saveFailed`.
140
+ */
141
+ onSaveScheduleInterval?: (row: TaskCenterImportRow, intervalMinutes: number) => Promise<void>;
142
+ /**
143
+ * 编译目标的定时规则保存。参数与原生 `update_schedule` 同形,宿主可直接转发。
144
+ * 成功与失败的处理同 {@link onSaveScheduleInterval}。
145
+ *
146
+ * Saving the schedule of a compile target. The argument matches the native
147
+ * `update_schedule`, so a host can forward it as-is. Success and failure are
148
+ * handled the same way as {@link onSaveScheduleInterval}.
149
+ */
150
+ onSaveCompileSchedule?: (row: TaskCenterCompileRow, schedule: TaskCenterCompileSchedule | null) => Promise<void>;
151
+ /**
152
+ * 插槽,见 {@link TaskCenterSlots}。
153
+ * Slots, see {@link TaskCenterSlots}.
154
+ */
155
+ slots?: TaskCenterSlots;
156
+ /**
157
+ * 可替换文案,缺省为英文。
158
+ * Replaceable copy; English by default.
159
+ */
160
+ labels?: TaskCenterLabels;
161
+ /**
162
+ * 请求配置覆盖,逐字段覆盖最近的 Provider。
163
+ * Request configuration override, applied field by field over the nearest
164
+ * Provider.
165
+ */
166
+ requestOptions?: OvRequestOptions;
167
+ }
168
+ export type { TaskCenterColumn, TaskCenterColumns, TaskCenterCompileColumnKey, TaskCenterCompileRow, TaskCenterCompileSchedule, TaskCenterImportColumnKey, TaskCenterImportRow, TaskCenterRow, } from './columns.js';
@@ -0,0 +1 @@
1
+ export { TaskCenter } from "../i~0.js";
package/dist/n~0.js ADDED
@@ -0,0 +1,499 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
3
+ function Chevron({ expanded }) {
4
+ return /*#__PURE__*/ jsx("svg", {
5
+ "aria-hidden": "true",
6
+ className: "ov-file-tree__chevron",
7
+ "data-expanded": expanded || void 0,
8
+ viewBox: "0 0 16 16",
9
+ width: "12",
10
+ height: "12",
11
+ children: /*#__PURE__*/ jsx("path", {
12
+ d: "M6 3.5 10.5 8 6 12.5",
13
+ fill: "none",
14
+ stroke: "currentColor",
15
+ strokeLinecap: "round",
16
+ strokeLinejoin: "round",
17
+ strokeWidth: "1.5"
18
+ })
19
+ });
20
+ }
21
+ function FolderIcon({ open }) {
22
+ return /*#__PURE__*/ jsx("svg", {
23
+ "aria-hidden": "true",
24
+ className: "ov-file-tree__icon",
25
+ viewBox: "0 0 16 16",
26
+ width: "14",
27
+ height: "14",
28
+ children: /*#__PURE__*/ jsx("path", {
29
+ d: open ? 'M1.5 13V4.5A1 1 0 0 1 2.5 3.5h3l1.2 1.5h5.8a1 1 0 0 1 1 1V7M1.5 13l1.6-5h11.4l-1.6 5H1.5Z' : 'M1.5 12.5v-9a1 1 0 0 1 1-1h3l1.2 1.5h6.8a1 1 0 0 1 1 1v7.5a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1Z',
30
+ fill: "none",
31
+ stroke: "currentColor",
32
+ strokeLinejoin: "round",
33
+ strokeWidth: "1.2"
34
+ })
35
+ });
36
+ }
37
+ function FileIcon() {
38
+ return /*#__PURE__*/ jsxs("svg", {
39
+ "aria-hidden": "true",
40
+ className: "ov-file-tree__icon",
41
+ viewBox: "0 0 16 16",
42
+ width: "14",
43
+ height: "14",
44
+ children: [
45
+ /*#__PURE__*/ jsx("path", {
46
+ d: "M4 1.5h5L12.5 5v9.5h-8.5V1.5Z",
47
+ fill: "none",
48
+ stroke: "currentColor",
49
+ strokeLinejoin: "round",
50
+ strokeWidth: "1.2"
51
+ }),
52
+ /*#__PURE__*/ jsx("path", {
53
+ d: "M9 1.5V5h3.5",
54
+ fill: "none",
55
+ stroke: "currentColor",
56
+ strokeWidth: "1.2"
57
+ })
58
+ ]
59
+ });
60
+ }
61
+ function Spinner() {
62
+ return /*#__PURE__*/ jsx("span", {
63
+ "aria-hidden": "true",
64
+ className: "ov-file-tree__spinner"
65
+ });
66
+ }
67
+ const DEFAULT_LABELS = {
68
+ empty: 'No files yet',
69
+ error: 'Failed to load',
70
+ retry: 'Retry',
71
+ loadMore: 'Load more',
72
+ loading: 'Loading…',
73
+ expand: 'Expand {name}',
74
+ collapse: 'Collapse {name}'
75
+ };
76
+ function fillName(template, name) {
77
+ return template.replace('{name}', name);
78
+ }
79
+ function rowIndent(row) {
80
+ return {
81
+ paddingLeft: `calc(${row.depth} * 16px)`
82
+ };
83
+ }
84
+ const FILE_TREE_ROW_ATTRIBUTE = 'data-file-tree-row-id';
85
+ function FileTreeEntryRowView({ row, ctx }) {
86
+ const { text, selectedId, tooltipRowId, getRowAttributes, renderDashboard, renderRowTooltip, onSelect, onToggleExpand, onOpenRetentionSettings, onRowKeyDown, onRowEnter, onRowLeave } = ctx;
87
+ const isDirectory = 'directory' === row.type;
88
+ const canExpand = isDirectory && false !== row.hasChildren;
89
+ const isSelected = selectedId === row.id;
90
+ const { className: extraClassName, style: extraStyle, ...extraAttributes } = getRowAttributes?.(row) ?? {};
91
+ const dashboard = renderDashboard?.(row) ?? null;
92
+ const tooltip = renderRowTooltip?.(row) ?? null;
93
+ const handleRowClick = (event)=>{
94
+ if (event.target.closest('[data-role="toggle"]')) return;
95
+ if (row.disabled) return;
96
+ onSelect?.(row);
97
+ };
98
+ return /*#__PURE__*/ jsxs("div", {
99
+ role: "treeitem",
100
+ tabIndex: 0,
101
+ "aria-level": row.depth + 1,
102
+ "aria-selected": isSelected,
103
+ "aria-expanded": canExpand ? Boolean(row.expanded) : void 0,
104
+ "aria-disabled": row.disabled || void 0,
105
+ ...extraAttributes,
106
+ [FILE_TREE_ROW_ATTRIBUTE]: row.id,
107
+ className: [
108
+ 'ov-file-tree__row',
109
+ extraClassName
110
+ ].filter(Boolean).join(' '),
111
+ "data-selected": isSelected || void 0,
112
+ "data-disabled": row.disabled || void 0,
113
+ "data-kind": row.kind,
114
+ style: {
115
+ ...rowIndent(row),
116
+ ...extraStyle
117
+ },
118
+ onClick: handleRowClick,
119
+ onKeyDown: (event)=>onRowKeyDown(event, row),
120
+ onMouseEnter: ()=>onRowEnter(row.id),
121
+ onMouseLeave: onRowLeave,
122
+ onFocus: ()=>onRowEnter(row.id),
123
+ onBlur: onRowLeave,
124
+ children: [
125
+ canExpand ? /*#__PURE__*/ jsx("button", {
126
+ type: "button",
127
+ "data-role": "toggle",
128
+ className: "ov-file-tree__toggle",
129
+ "aria-label": fillName(row.expanded ? text.collapse : text.expand, row.name),
130
+ tabIndex: -1,
131
+ disabled: !onToggleExpand || row.disabled || row.busy,
132
+ onClick: (event)=>{
133
+ event.stopPropagation();
134
+ onToggleExpand?.(row);
135
+ },
136
+ children: /*#__PURE__*/ jsx(Chevron, {
137
+ expanded: Boolean(row.expanded)
138
+ })
139
+ }) : /*#__PURE__*/ jsx("span", {
140
+ "aria-hidden": "true",
141
+ className: "ov-file-tree__toggle-spacer"
142
+ }),
143
+ /*#__PURE__*/ jsx("span", {
144
+ className: "ov-file-tree__icon-slot",
145
+ children: isDirectory ? /*#__PURE__*/ jsx(FolderIcon, {
146
+ open: Boolean(row.expanded)
147
+ }) : /*#__PURE__*/ jsx(FileIcon, {})
148
+ }),
149
+ /*#__PURE__*/ jsxs("span", {
150
+ className: "ov-file-tree__label-group",
151
+ children: [
152
+ /*#__PURE__*/ jsx("span", {
153
+ className: "ov-file-tree__label",
154
+ title: row.name,
155
+ children: row.name
156
+ }),
157
+ row.description ? /*#__PURE__*/ jsx("span", {
158
+ className: "ov-file-tree__description",
159
+ children: row.description
160
+ }) : null
161
+ ]
162
+ }),
163
+ row.busy ? /*#__PURE__*/ jsx(Spinner, {}) : null,
164
+ row.expiresAt ? /*#__PURE__*/ jsx("span", {
165
+ className: "ov-file-tree__expiry",
166
+ title: row.expiresAt,
167
+ children: onOpenRetentionSettings ? /*#__PURE__*/ jsx("button", {
168
+ type: "button",
169
+ className: "ov-file-tree__expiry-action",
170
+ onClick: (event)=>{
171
+ event.stopPropagation();
172
+ onOpenRetentionSettings(row.uri);
173
+ },
174
+ children: row.expiresAt
175
+ }) : row.expiresAt
176
+ }) : null,
177
+ row.levelLabel ? /*#__PURE__*/ jsx("span", {
178
+ className: "ov-file-tree__level",
179
+ children: row.levelLabel
180
+ }) : null,
181
+ dashboard ? /*#__PURE__*/ jsx("span", {
182
+ className: "ov-file-tree__dashboard",
183
+ children: dashboard
184
+ }) : null,
185
+ tooltip && tooltipRowId === row.id ? /*#__PURE__*/ jsx("span", {
186
+ role: "tooltip",
187
+ className: "ov-file-tree__tooltip",
188
+ children: tooltip
189
+ }) : null
190
+ ]
191
+ });
192
+ }
193
+ function isWholeTreeError(rows) {
194
+ if (1 !== rows.length) return false;
195
+ const [row] = rows;
196
+ return row?.kind === 'error' && !row.parentId;
197
+ }
198
+ function StateRow({ row, ctx, attributes, tone, children }) {
199
+ const { className: extraClassName, style: extraStyle, ...extraAttributes } = ctx.getRowAttributes?.(row) ?? {};
200
+ return /*#__PURE__*/ jsx("div", {
201
+ role: "treeitem",
202
+ "aria-level": row.depth + 1,
203
+ "aria-selected": false,
204
+ ...attributes,
205
+ ...extraAttributes,
206
+ [FILE_TREE_ROW_ATTRIBUTE]: row.id,
207
+ className: [
208
+ 'ov-file-tree__child-row',
209
+ extraClassName
210
+ ].filter(Boolean).join(' '),
211
+ "data-tone": tone,
212
+ style: {
213
+ ...rowIndent(row),
214
+ ...extraStyle
215
+ },
216
+ children: children
217
+ });
218
+ }
219
+ function ChildRow({ row, ctx }) {
220
+ const { text, onLoadMore, onRetry } = ctx;
221
+ switch(row.kind){
222
+ case 'loading':
223
+ return /*#__PURE__*/ jsxs(StateRow, {
224
+ row: row,
225
+ ctx: ctx,
226
+ attributes: {
227
+ 'aria-busy': true
228
+ },
229
+ children: [
230
+ /*#__PURE__*/ jsx("span", {
231
+ className: "ov-file-tree__toggle-spacer"
232
+ }),
233
+ /*#__PURE__*/ jsx(Spinner, {}),
234
+ /*#__PURE__*/ jsx("span", {
235
+ className: "ov-file-tree__muted",
236
+ children: text.loading
237
+ })
238
+ ]
239
+ });
240
+ case 'load-more':
241
+ return /*#__PURE__*/ jsx(StateRow, {
242
+ row: row,
243
+ ctx: ctx,
244
+ children: /*#__PURE__*/ jsxs("button", {
245
+ type: "button",
246
+ className: "ov-file-tree__child-action",
247
+ disabled: row.loading || !onLoadMore,
248
+ onClick: ()=>onLoadMore?.(row),
249
+ children: [
250
+ row.loading ? /*#__PURE__*/ jsx(Spinner, {}) : null,
251
+ text.loadMore
252
+ ]
253
+ })
254
+ });
255
+ case 'error':
256
+ return /*#__PURE__*/ jsxs(StateRow, {
257
+ row: row,
258
+ ctx: ctx,
259
+ tone: "error",
260
+ children: [
261
+ /*#__PURE__*/ jsx("span", {
262
+ className: "ov-file-tree__muted",
263
+ children: row.message ?? text.error
264
+ }),
265
+ /*#__PURE__*/ jsx("button", {
266
+ type: "button",
267
+ className: "ov-file-tree__child-action",
268
+ disabled: !onRetry,
269
+ onClick: ()=>onRetry?.(row),
270
+ children: text.retry
271
+ })
272
+ ]
273
+ });
274
+ case 'empty':
275
+ return /*#__PURE__*/ jsx(StateRow, {
276
+ row: row,
277
+ ctx: ctx,
278
+ children: /*#__PURE__*/ jsx("span", {
279
+ className: "ov-file-tree__muted",
280
+ children: text.empty
281
+ })
282
+ });
283
+ default:
284
+ return /*#__PURE__*/ jsx(FileTreeEntryRowView, {
285
+ row: row,
286
+ ctx: ctx
287
+ });
288
+ }
289
+ }
290
+ function FileTreeRowView({ row, ctx }) {
291
+ return /*#__PURE__*/ jsx(ChildRow, {
292
+ row: row,
293
+ ctx: ctx
294
+ });
295
+ }
296
+ function FileTreeBody({ rows, isReady, text, loadingFallback, errorFallback, emptyFallback, ctx }) {
297
+ if (!isReady) return /*#__PURE__*/ jsx("div", {
298
+ className: "ov-file-tree__state",
299
+ children: loadingFallback ?? /*#__PURE__*/ jsx("span", {
300
+ className: "ov-file-tree__muted",
301
+ children: text.loading
302
+ })
303
+ });
304
+ if (isWholeTreeError(rows)) {
305
+ const message = rows[0].message ?? text.error;
306
+ return /*#__PURE__*/ jsx("div", {
307
+ className: "ov-file-tree__state",
308
+ children: errorFallback ?? /*#__PURE__*/ jsx("span", {
309
+ className: "ov-file-tree__muted",
310
+ children: message
311
+ })
312
+ });
313
+ }
314
+ if (0 === rows.length) return /*#__PURE__*/ jsx("div", {
315
+ className: "ov-file-tree__state",
316
+ children: emptyFallback ?? /*#__PURE__*/ jsx("span", {
317
+ className: "ov-file-tree__muted",
318
+ children: text.empty
319
+ })
320
+ });
321
+ return /*#__PURE__*/ jsx("div", {
322
+ role: "group",
323
+ className: "ov-file-tree__rows",
324
+ children: rows.map((row)=>/*#__PURE__*/ jsx(FileTreeRowView, {
325
+ row: row,
326
+ ctx: ctx
327
+ }, row.id))
328
+ });
329
+ }
330
+ function queryRowElements(root) {
331
+ if (!root) return [];
332
+ return Array.from(root.querySelectorAll(`[${FILE_TREE_ROW_ATTRIBUTE}]`));
333
+ }
334
+ function findRowElement(root, id) {
335
+ if (!root) return null;
336
+ return root.querySelector(`[${FILE_TREE_ROW_ATTRIBUTE}="${CSS.escape(id)}"]`);
337
+ }
338
+ function moveFocus(current, root, delta) {
339
+ const elements = queryRowElements(root);
340
+ const index = elements.indexOf(current);
341
+ if (-1 === index) return;
342
+ elements[index + delta]?.focus();
343
+ }
344
+ function handleRowKeyDown(event, { root, row, onSelect, onToggleExpand }) {
345
+ switch(event.key){
346
+ case 'ArrowDown':
347
+ event.preventDefault();
348
+ moveFocus(event.currentTarget, root, 1);
349
+ break;
350
+ case 'ArrowUp':
351
+ event.preventDefault();
352
+ moveFocus(event.currentTarget, root, -1);
353
+ break;
354
+ case 'ArrowRight':
355
+ if (!row.disabled && !row.busy && 'directory' === row.type && !row.expanded) {
356
+ event.preventDefault();
357
+ onToggleExpand?.(row);
358
+ }
359
+ break;
360
+ case 'ArrowLeft':
361
+ if (!row.disabled && !row.busy && 'directory' === row.type && row.expanded) {
362
+ event.preventDefault();
363
+ onToggleExpand?.(row);
364
+ }
365
+ break;
366
+ case 'Enter':
367
+ case ' ':
368
+ event.preventDefault();
369
+ if (!row.disabled) onSelect?.(row);
370
+ break;
371
+ default:
372
+ break;
373
+ }
374
+ }
375
+ function useRowTooltip(delay = 400) {
376
+ const [tooltipRowId, setTooltipRowId] = useState(null);
377
+ const timerRef = useRef(void 0);
378
+ useEffect(()=>()=>{
379
+ if (void 0 !== timerRef.current) window.clearTimeout(timerRef.current);
380
+ }, []);
381
+ const show = useCallback((rowId)=>{
382
+ if (void 0 !== timerRef.current) window.clearTimeout(timerRef.current);
383
+ timerRef.current = window.setTimeout(()=>{
384
+ setTooltipRowId(rowId);
385
+ timerRef.current = void 0;
386
+ }, delay);
387
+ }, [
388
+ delay
389
+ ]);
390
+ const hide = useCallback(()=>{
391
+ if (void 0 !== timerRef.current) {
392
+ window.clearTimeout(timerRef.current);
393
+ timerRef.current = void 0;
394
+ }
395
+ setTooltipRowId(null);
396
+ }, []);
397
+ return {
398
+ tooltipRowId,
399
+ show,
400
+ hide
401
+ };
402
+ }
403
+ function useFileTreeActions(props) {
404
+ const pending = useRef(new Set());
405
+ const { select, toggleExpand, loadMore, retry, openRetentionSettings } = props.operations ?? {};
406
+ async function run(key, execute, notify, value) {
407
+ if (pending.current.has(key)) return;
408
+ pending.current.add(key);
409
+ try {
410
+ await execute(value);
411
+ } catch {
412
+ return;
413
+ } finally{
414
+ pending.current.delete(key);
415
+ }
416
+ notify?.(value);
417
+ }
418
+ return {
419
+ onSelect: select ? (row)=>void run(`select:${row.id}`, select, props.onSelect, row) : void 0,
420
+ onToggleExpand: toggleExpand ? (row)=>void run(`toggle:${row.id}`, toggleExpand, props.onToggleExpand, row) : void 0,
421
+ onLoadMore: loadMore ? (row)=>void run(`load:${row.id}`, loadMore, props.onLoadMore, row) : void 0,
422
+ onRetry: retry ? (row)=>void run(`retry:${row.id}`, retry, props.onRetry, row) : void 0,
423
+ onOpenRetentionSettings: openRetentionSettings ? (uri)=>void run(`retention:${uri}`, openRetentionSettings, props.onOpenRetentionSettings, uri) : void 0
424
+ };
425
+ }
426
+ const file_tree_FileTree = /*#__PURE__*/ forwardRef(function({ rows, operations, selectedId, isReady = true, loadingFallback, errorFallback, emptyFallback, slots, labels, getRowAttributes, renderDashboard, renderRowTooltip, onSelect, onToggleExpand, onLoadMore, onRetry, onOpenRetentionSettings, className, ...rest }, ref) {
427
+ const rootRef = useRef(null);
428
+ const text = {
429
+ ...DEFAULT_LABELS,
430
+ ...labels
431
+ };
432
+ const tooltip = useRowTooltip();
433
+ const actions = useFileTreeActions({
434
+ operations,
435
+ onSelect,
436
+ onToggleExpand,
437
+ onLoadMore,
438
+ onRetry,
439
+ onOpenRetentionSettings
440
+ });
441
+ useImperativeHandle(ref, ()=>({
442
+ getRowElement: (id)=>findRowElement(rootRef.current, id),
443
+ scrollToRow: (id, options)=>{
444
+ const element = findRowElement(rootRef.current, id);
445
+ if (!element) return false;
446
+ element.scrollIntoView({
447
+ block: 'nearest',
448
+ ...options
449
+ });
450
+ return true;
451
+ }
452
+ }), []);
453
+ const rowContext = {
454
+ text,
455
+ selectedId,
456
+ tooltipRowId: tooltip.tooltipRowId,
457
+ getRowAttributes,
458
+ renderDashboard,
459
+ renderRowTooltip,
460
+ ...actions,
461
+ onRowKeyDown: (event, row)=>handleRowKeyDown(event, {
462
+ root: rootRef.current,
463
+ row,
464
+ onSelect: actions.onSelect,
465
+ onToggleExpand: actions.onToggleExpand
466
+ }),
467
+ onRowEnter: tooltip.show,
468
+ onRowLeave: tooltip.hide
469
+ };
470
+ return /*#__PURE__*/ jsxs("div", {
471
+ ...rest,
472
+ ref: rootRef,
473
+ className: [
474
+ 'ov-file-tree',
475
+ className
476
+ ].filter(Boolean).join(' '),
477
+ children: [
478
+ slots?.toolbar ? /*#__PURE__*/ jsx("div", {
479
+ className: "ov-file-tree__toolbar",
480
+ children: slots.toolbar
481
+ }) : null,
482
+ /*#__PURE__*/ jsx("div", {
483
+ role: "tree",
484
+ "aria-label": rest['aria-label'],
485
+ className: "ov-file-tree__body",
486
+ children: /*#__PURE__*/ jsx(FileTreeBody, {
487
+ rows: rows,
488
+ isReady: isReady,
489
+ text: text,
490
+ loadingFallback: loadingFallback,
491
+ errorFallback: errorFallback,
492
+ emptyFallback: emptyFallback,
493
+ ctx: rowContext
494
+ })
495
+ })
496
+ ]
497
+ });
498
+ });
499
+ export { FILE_TREE_ROW_ATTRIBUTE, file_tree_FileTree as FileTree };