@openviking/react 0.1.6 → 0.1.7

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 (94) hide show
  1. package/README.md +2 -0
  2. package/dist/2~0.js +6 -5
  3. package/dist/3c~0.js +10 -4
  4. package/dist/3~0.js +18 -8
  5. package/dist/ae~0.js +8 -1
  6. package/dist/ark-message-list-view~0.js +9 -4
  7. package/dist/a~0.js +12 -6
  8. package/dist/c7r~0.js +50 -0
  9. package/dist/ck~0.js +3 -0
  10. package/dist/client/paths.d.ts +6 -0
  11. package/dist/client/provider.d.ts +6 -1
  12. package/dist/components/agent-connect/style.css +222 -35
  13. package/dist/components/directory-tour/style.css +221 -21
  14. package/dist/components/directory-tour.js +1 -1
  15. package/dist/components/experience-dashboard/style.css +227 -12
  16. package/dist/components/experience-dashboard.js +1 -1
  17. package/dist/components/file-browser-entries/style.css +325 -80
  18. package/dist/components/file-preview/style.css +221 -76
  19. package/dist/components/file-tree/file-tree-toolbar.d.ts +3 -3
  20. package/dist/components/file-tree/locales/en-US.d.ts +3 -0
  21. package/dist/components/file-tree/locales/zh-CN.d.ts +3 -0
  22. package/dist/components/file-tree/style.css +311 -86
  23. package/dist/components/file-tree/types.d.ts +13 -4
  24. package/dist/components/scope-switcher/style.css +366 -37
  25. package/dist/components/scope-switcher.js +1 -1
  26. package/dist/components/style.css +3329 -640
  27. package/dist/components/tui/style.css +267 -35
  28. package/dist/components/viking-bot/interaction/style.css +143 -22
  29. package/dist/components/viking-bot/style.css +945 -295
  30. package/dist/components/wiki-dashboard/style.css +227 -12
  31. package/dist/c~0.js +16 -8
  32. package/dist/ep~0.js +345 -0
  33. package/dist/e~0.js +33 -328
  34. package/dist/fj~0.js +8 -4
  35. package/dist/fl~0.js +709 -0
  36. package/dist/f~0.js +302 -663
  37. package/dist/index.js +3 -3
  38. package/dist/lk~0.js +6 -3
  39. package/dist/l~0.js +1874 -437
  40. package/dist/modules/console/style.css +1471 -351
  41. package/dist/modules/file-browser/acl/acl-add-principal.d.ts +12 -0
  42. package/dist/modules/file-browser/acl/acl-candidate.d.ts +8 -0
  43. package/dist/modules/file-browser/acl/acl-client.d.ts +13 -0
  44. package/dist/modules/file-browser/acl/acl-confirmation.d.ts +6 -0
  45. package/dist/modules/file-browser/acl/acl-entry.d.ts +13 -0
  46. package/dist/modules/file-browser/acl/acl-labels.d.ts +47 -0
  47. package/dist/modules/file-browser/acl/acl-menu.d.ts +10 -0
  48. package/dist/modules/file-browser/acl/acl-modal.d.ts +17 -0
  49. package/dist/modules/file-browser/acl/acl-model.d.ts +17 -0
  50. package/dist/modules/file-browser/acl/acl-principal-tabs.d.ts +6 -0
  51. package/dist/modules/file-browser/acl/acl-tag.d.ts +7 -0
  52. package/dist/modules/file-browser/acl/locales/en-US.d.ts +44 -0
  53. package/dist/modules/file-browser/acl/locales/zh-CN.d.ts +44 -0
  54. package/dist/modules/file-browser/acl/use-acl-principals.d.ts +17 -0
  55. package/dist/modules/file-browser/acl/use-acl-report.d.ts +27 -0
  56. package/dist/modules/file-browser/acl-types.d.ts +86 -0
  57. package/dist/modules/file-browser/dashboard-model.d.ts +3 -0
  58. package/dist/modules/file-browser/file-browser-detail.d.ts +4 -1
  59. package/dist/modules/file-browser/file-browser-labels.d.ts +1 -1
  60. package/dist/modules/file-browser/file-browser-search.d.ts +20 -0
  61. package/dist/modules/file-browser/file-browser-toolbar.d.ts +3 -10
  62. package/dist/modules/file-browser/file-browser-tree-pane.d.ts +2 -6
  63. package/dist/modules/file-browser/file-browser.d.ts +1 -1
  64. package/dist/modules/file-browser/fs-directories.d.ts +1 -0
  65. package/dist/modules/file-browser/fs-model.d.ts +3 -1
  66. package/dist/modules/file-browser/index.d.ts +1 -0
  67. package/dist/modules/file-browser/locales/en-US.d.ts +5 -0
  68. package/dist/modules/file-browser/locales/zh-CN.d.ts +5 -0
  69. package/dist/modules/file-browser/style.css +2409 -603
  70. package/dist/modules/file-browser/types.d.ts +20 -20
  71. package/dist/modules/file-browser/use-file-browser-acl.d.ts +15 -0
  72. package/dist/modules/file-browser/use-file-browser.d.ts +5 -7
  73. package/dist/modules/file-browser/use-fs-tree.d.ts +1 -0
  74. package/dist/modules/scope-cascade/style.css +535 -37
  75. package/dist/modules/style.css +12227 -8757
  76. package/dist/n~0.js +60 -36
  77. package/dist/rt~0.js +107 -4
  78. package/dist/r~0.js +1 -1
  79. package/dist/shared/components/button/button.d.ts +20 -0
  80. package/dist/shared/components/input/input.d.ts +17 -0
  81. package/dist/shared/components/modal/locales/en-US.d.ts +4 -0
  82. package/dist/shared/components/modal/locales/zh-CN.d.ts +4 -0
  83. package/dist/shared/components/modal/modal.d.ts +2 -0
  84. package/dist/shared/components/modal/types.d.ts +18 -0
  85. package/dist/shared/components/overlay/lock-body-scroll.d.ts +1 -0
  86. package/dist/style.css +7776 -1571
  87. package/dist/s~0.js +16 -0
  88. package/dist/u~0.js +15 -6
  89. package/dist/viking-bot-composer~0.js +29 -11
  90. package/dist/viking-bot-interaction~0.js +2 -1
  91. package/package.json +3 -2
  92. package/dist/fi~0.js +0 -354
  93. package/dist/modules/file-browser/fs-selection.d.ts +0 -4
  94. package/dist/o~0.js +0 -106
package/dist/f~0.js CHANGED
@@ -1,700 +1,339 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useId, useState } from "react";
3
- import { mergeLabels } from "./nx~0.js";
4
- import { FileInputIcon, ScanSearchIcon, ActivityIcon } from "./k~0.js";
5
- import { DashboardState } from "./37~0.js";
6
- import { useLocale } from "./28~0.js";
7
- function DashboardTabs({ tabs, active, label, onChange, children }) {
8
- const id = useId();
9
- return /*#__PURE__*/ jsxs(Fragment, {
10
- children: [
11
- /*#__PURE__*/ jsx("div", {
12
- className: "ov-dashboard-tabs",
13
- role: "tablist",
14
- tabIndex: -1,
15
- "aria-label": label,
16
- onKeyDown: (event)=>{
17
- const delta = 'ArrowRight' === event.key ? 1 : 'ArrowLeft' === event.key ? -1 : 0;
18
- if (!delta && 'Home' !== event.key && 'End' !== event.key) return;
19
- event.preventDefault();
20
- const index = 'Home' === event.key ? 0 : 'End' === event.key ? tabs.length - 1 : (tabs.findIndex((tab)=>tab.key === active) + delta + tabs.length) % tabs.length;
21
- onChange(tabs[index].key);
22
- const buttons = event.currentTarget.querySelectorAll('[role="tab"]');
23
- buttons[index]?.focus();
24
- },
25
- children: tabs.map((tab)=>/*#__PURE__*/ jsx("button", {
26
- type: "button",
27
- id: `${id}-${tab.key}`,
28
- role: "tab",
29
- "aria-selected": active === tab.key,
30
- "aria-controls": `${id}-panel`,
31
- tabIndex: active === tab.key ? 0 : -1,
32
- onClick: ()=>onChange(tab.key),
33
- children: tab.title
34
- }, tab.key))
35
- }),
36
- /*#__PURE__*/ jsx("div", {
37
- role: "tabpanel",
38
- id: `${id}-panel`,
39
- "aria-labelledby": `${id}-${active}`,
40
- className: "ov-dashboard-tabpanel",
41
- children: children
42
- })
43
- ]
44
- });
45
- }
46
- const en = {
47
- latest: 'Latest experience',
48
- sourceCount: 'Generated from {count} trajectories',
49
- sourceUri: 'Source Trajectory URI',
50
- task: 'Task',
51
- copy: 'Copy',
52
- copied: 'Copied',
53
- copyFailed: 'Copy failed',
54
- title: 'Agent experiences',
55
- allExperiences: 'All experiences',
56
- index: 'No.',
57
- impact: 'Application impact',
58
- source: 'Source trace',
59
- test: 'Test',
60
- application: 'Experience application data',
61
- notice: 'AI-generated data may contain errors',
62
- injection: 'Context injections',
63
- recall: 'Retrieval recalls',
64
- listRecall: 'Experience recalls',
65
- rate: 'Injection rate',
66
- outcomes: 'Outcome distribution',
67
- trajectories: 'Application trajectories',
68
- empty: 'No experiences',
69
- emptySource: 'No source records',
70
- emptyTests: 'No test materials',
71
- emptyOutcomes: 'No distribution data',
2
+ import { useCallback, useEffect, useId, useRef, useState } from "react";
3
+ import { resolveLocale } from "./nx~0.js";
4
+ import { checkreact } from "./0~0.js";
5
+ import { searchreact } from "./p~0.js";
6
+ import { input_Input } from "./c7r~0.js";
7
+ import { chevron_downreact } from "./s~0.js";
8
+ import { useLocale, LocaleProvider } from "./28~0.js";
9
+ const messages = {
72
10
  loading: 'Loading…',
73
- failed: 'Could not load data',
74
- retry: 'Retry',
75
- previous: 'Previous',
76
- next: 'Next',
77
- all: 'All time',
78
- week: 'Last 7 days',
79
- month: 'Last 30 days',
80
- range: 'Statistics period',
81
- updated: 'Updated',
82
- name: 'Experience',
83
- success: 'Task success',
84
- partial: 'Partial success',
85
- unfinished: 'Unfinished',
86
- failure: 'Failure',
87
- unknown: 'Unknown',
88
- unsupportedMetric: 'Metric not provided',
89
- open: 'Open'
11
+ searchPlaceholder: 'Search',
12
+ empty: 'No options',
13
+ noMatch: 'No matches',
14
+ error: 'Unable to load options'
90
15
  };
91
- const zh = {
92
- latest: '最新经验',
93
- sourceCount: '由 {count} 条轨迹生成',
94
- sourceUri: '来源 Trajectory URI',
95
- task: '任务描述',
96
- copy: '复制',
97
- copied: '已复制',
98
- copyFailed: '复制失败',
99
- title: 'Agent 经验',
100
- allExperiences: '全部经验',
101
- index: '序号',
102
- impact: '应用效果',
103
- source: '来源追溯',
104
- test: '测试',
105
- application: '经验应用数据',
106
- notice: '数据由 AI 生成,可能有误',
107
- injection: '注入上下文次数',
108
- recall: '检索召回次数',
109
- listRecall: '经验召回次数',
110
- rate: '注入率',
111
- outcomes: '任务结果分布',
112
- trajectories: '应用轨迹记录',
113
- empty: '暂无经验',
114
- emptySource: '暂无来源记录',
115
- emptyTests: '暂无测试材料',
116
- emptyOutcomes: '暂无可用分布数据',
16
+ const en_US = messages;
17
+ const zh_CN_messages = {
117
18
  loading: '加载中…',
118
- failed: '数据加载失败',
119
- retry: '重试',
120
- previous: '上一页',
121
- next: '下一页',
122
- all: '全部时间',
123
- week: '最近 7 天',
124
- month: '最近 30 天',
125
- range: '选择统计时间范围',
126
- updated: '更新于',
127
- name: '经验文件',
128
- success: '任务成功',
129
- partial: '部分成功',
130
- unfinished: '未完成',
131
- failure: '失败',
132
- unknown: '未知',
133
- unsupportedMetric: '未提供此指标',
134
- open: '打开'
19
+ searchPlaceholder: '搜索',
20
+ empty: '暂无选项',
21
+ noMatch: '没有匹配项',
22
+ error: '选项加载失败'
23
+ };
24
+ const zh_CN = zh_CN_messages;
25
+ const LOCALES = {
26
+ 'en-US': en_US,
27
+ 'zh-CN': zh_CN
135
28
  };
136
- const experienceLabels = (locale, labels)=>mergeLabels('zh-CN' === locale ? zh : en, labels);
137
- function updatedAt(value, locale) {
138
- const time = Date.parse(value);
139
- if (!Number.isFinite(time)) return value;
140
- const seconds = (time - Date.now()) / 1000;
141
- const absolute = Math.abs(seconds);
142
- if (absolute >= 604800) return new Intl.DateTimeFormat(locale).format(time);
143
- const [unit, size] = absolute < 3600 ? [
144
- 'minute',
145
- 60
146
- ] : absolute < 86400 ? [
147
- 'hour',
148
- 3600
149
- ] : [
150
- 'day',
151
- 86400
152
- ];
153
- return new Intl.RelativeTimeFormat(locale, {
154
- numeric: 'always'
155
- }).format(Math.round(seconds / size), unit);
29
+ function resolveScopeLabels(locale = 'en-US', labels) {
30
+ const defaults = resolveLocale(LOCALES, locale, labels);
31
+ return {
32
+ ...defaults,
33
+ noMatch: labels?.noMatch ?? labels?.empty ?? defaults.noMatch
34
+ };
156
35
  }
157
- function ExperienceList({ items, total, startIndex = 0, locale = 'en-US', labels: t, onOpenUri }) {
158
- return /*#__PURE__*/ jsxs(Fragment, {
159
- children: [
160
- /*#__PURE__*/ jsxs("h2", {
161
- className: "ov-experience-dashboard__list-title",
162
- children: [
163
- t.allExperiences,
164
- void 0 === total ? '' : ` · ${total}`
165
- ]
166
- }),
167
- /*#__PURE__*/ jsx("div", {
168
- className: "ov-experience-dashboard__table-scroll",
169
- tabIndex: 0,
170
- role: "region",
171
- "aria-label": t.title,
172
- children: /*#__PURE__*/ jsxs("table", {
173
- className: "ov-experience-dashboard__table",
174
- children: [
175
- /*#__PURE__*/ jsx("caption", {
176
- children: t.title
177
- }),
178
- /*#__PURE__*/ jsx("thead", {
179
- children: /*#__PURE__*/ jsxs("tr", {
180
- children: [
181
- /*#__PURE__*/ jsx("th", {
182
- scope: "col",
183
- children: t.index
184
- }),
185
- /*#__PURE__*/ jsx("th", {
186
- scope: "col",
187
- children: t.name
188
- }),
189
- /*#__PURE__*/ jsx("th", {
190
- scope: "col",
191
- children: t.injection
192
- }),
193
- /*#__PURE__*/ jsx("th", {
194
- scope: "col",
195
- children: t.listRecall
196
- })
197
- ]
198
- })
199
- }),
200
- /*#__PURE__*/ jsx("tbody", {
201
- children: items.map((item, index)=>/*#__PURE__*/ jsxs("tr", {
202
- children: [
203
- /*#__PURE__*/ jsxs("td", {
204
- children: [
205
- "# ",
206
- startIndex + index + 1
207
- ]
208
- }),
209
- /*#__PURE__*/ jsxs("th", {
210
- scope: "row",
211
- children: [
212
- /*#__PURE__*/ jsx("button", {
213
- type: "button",
214
- disabled: !onOpenUri,
215
- onClick: ()=>onOpenUri?.(item.uri),
216
- children: item.name
217
- }),
218
- /*#__PURE__*/ jsxs("span", {
219
- children: [
220
- /*#__PURE__*/ jsx("code", {
221
- title: item.uri,
222
- children: item.uri
223
- }),
224
- item.modTime ? /*#__PURE__*/ jsxs("time", {
225
- dateTime: item.modTime,
226
- title: item.modTime,
227
- children: [
228
- "\xb7 ",
229
- t.updated,
230
- " ",
231
- updatedAt(item.modTime, locale)
232
- ]
233
- }) : null
234
- ]
235
- })
236
- ]
237
- }),
238
- /*#__PURE__*/ jsx("td", {
239
- children: item.injectionCount ?? '—'
240
- }),
241
- /*#__PURE__*/ jsx("td", {
242
- children: item.recallCount ?? '—'
243
- })
244
- ]
245
- }, item.uri))
246
- })
247
- ]
248
- })
249
- })
250
- ]
251
- });
36
+ function moveScopeFocus(event) {
37
+ if (![
38
+ 'ArrowDown',
39
+ 'ArrowUp',
40
+ 'Home',
41
+ 'End'
42
+ ].includes(event.key)) return;
43
+ const target = event.target;
44
+ const isSearch = target.matches('input.ov-scope-switcher__search');
45
+ if (event.defaultPrevented || !target.matches('[role="option"]') && !isSearch || isSearch && !event.key.startsWith('Arrow')) return;
46
+ const options = Array.from(event.currentTarget.querySelectorAll('[role="option"]:not([aria-disabled="true"])'));
47
+ if (!options.length) return;
48
+ event.preventDefault();
49
+ const current = options.indexOf(document.activeElement);
50
+ const next = 'Home' === event.key ? 0 : 'End' === event.key ? options.length - 1 : 'ArrowDown' === event.key ? (current + 1) % options.length : current < 0 ? options.length - 1 : (current - 1 + options.length) % options.length;
51
+ options[next]?.focus();
252
52
  }
253
- function ExperienceTrajectories({ items, onOpenUri, source = false }) {
254
- return /*#__PURE__*/ jsx("ul", {
255
- className: `ov-experience-dashboard__timeline${source ? ' ov-experience-dashboard__timeline--source' : ''}`,
256
- children: items.map((item)=>/*#__PURE__*/ jsxs("li", {
257
- children: [
258
- item.created_at ? /*#__PURE__*/ jsx("time", {
259
- dateTime: item.created_at,
260
- children: item.created_at
261
- }) : null,
262
- /*#__PURE__*/ jsx("button", {
263
- type: "button",
264
- disabled: !onOpenUri,
265
- onClick: ()=>onOpenUri?.(item.uri),
266
- children: item.name
267
- }),
268
- /*#__PURE__*/ jsx("code", {
269
- children: item.uri
270
- }),
271
- item.description ? /*#__PURE__*/ jsx("p", {
272
- children: item.description
273
- }) : null
274
- ]
275
- }, item.uri))
53
+ function Highlight({ text, keyword }) {
54
+ const needle = keyword.trim().toLocaleLowerCase();
55
+ if (!needle) return /*#__PURE__*/ jsx(Fragment, {
56
+ children: text
57
+ });
58
+ const haystack = text.toLocaleLowerCase();
59
+ const parts = [];
60
+ let cursor = 0;
61
+ let hit = haystack.indexOf(needle);
62
+ while(hit >= 0){
63
+ if (hit > cursor) parts.push(text.slice(cursor, hit));
64
+ const end = hit + needle.length;
65
+ parts.push(/*#__PURE__*/ jsx("mark", {
66
+ children: text.slice(hit, end)
67
+ }, `${hit}-${end}`));
68
+ cursor = end;
69
+ hit = haystack.indexOf(needle, cursor);
70
+ }
71
+ if (cursor < text.length) parts.push(text.slice(cursor));
72
+ return /*#__PURE__*/ jsx(Fragment, {
73
+ children: parts
276
74
  });
277
75
  }
278
- const ORDER = [
279
- 'success',
280
- 'partial',
281
- 'unfinished',
282
- 'failure',
283
- 'unknown'
284
- ];
285
- function ExperienceImpact({ data, labels: t, days, onDaysChange, outcomesState, trajectoriesState, onOpenUri }) {
286
- const total = data.outcomes?.reduce((sum, item)=>sum + item.count, 0) ?? 0;
287
- const metrics = [
288
- {
289
- label: t.injection,
290
- value: data.effect?.injectionCount,
291
- icon: /*#__PURE__*/ jsx(FileInputIcon, {
292
- width: 14,
293
- height: 14
294
- })
295
- },
296
- {
297
- label: t.recall,
298
- value: data.effect?.recallCount,
299
- icon: /*#__PURE__*/ jsx(ScanSearchIcon, {
300
- width: 14,
301
- height: 14
302
- })
76
+ function ScopePanel({ label, data, state, slots, actions, onSelect, labels }) {
77
+ const focusPanel = useCallback((node)=>{
78
+ const target = node?.querySelector('input') ?? node?.querySelector('[role="option"][aria-selected="true"]:not([aria-disabled="true"])') ?? node?.querySelector('[role="option"]:not([aria-disabled="true"])');
79
+ (target ?? node)?.focus();
80
+ }, []);
81
+ const options = data.visibleOptions ?? data.options;
82
+ const keyword = state?.searchKeyword ?? '';
83
+ const hasKeyword = keyword.trim().length > 0;
84
+ const searchVisible = actions?.onSearchKeywordChange && (hasKeyword || Math.max(options.length, data.options.length, data.total ?? 0) > 10);
85
+ const search = searchVisible ? /*#__PURE__*/ jsx(input_Input, {
86
+ size: "small",
87
+ prefix: /*#__PURE__*/ jsx(searchreact, {
88
+ className: "ov-scope-switcher__search-icon"
89
+ }),
90
+ type: "search",
91
+ className: "ov-scope-switcher__search-field",
92
+ value: keyword,
93
+ "aria-label": labels.searchPlaceholder,
94
+ placeholder: labels.searchPlaceholder,
95
+ onChange: (event)=>actions?.onSearchKeywordChange?.(event.currentTarget.value)
96
+ }) : null;
97
+ let list;
98
+ list = state?.loading ? /*#__PURE__*/ jsx("div", {
99
+ className: "ov-scope-switcher__state",
100
+ role: "status",
101
+ children: labels.loading
102
+ }) : state?.error ? /*#__PURE__*/ jsx("div", {
103
+ className: "ov-scope-switcher__state",
104
+ role: "alert",
105
+ children: slots?.errorFallback ?? labels.error
106
+ }) : options.length ? /*#__PURE__*/ jsx("div", {
107
+ className: "ov-scope-switcher__list",
108
+ role: "listbox",
109
+ "aria-label": label,
110
+ "aria-busy": state?.busy,
111
+ onScroll: (event)=>{
112
+ const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
113
+ actions?.onScroll?.({
114
+ scrollTop,
115
+ scrollHeight,
116
+ clientHeight
117
+ });
303
118
  },
304
- {
305
- label: t.rate,
306
- value: data.effect ? new Intl.NumberFormat('en-US', {
307
- style: 'percent',
308
- maximumFractionDigits: 1
309
- }).format(data.effect.injectionRate) : void 0,
310
- icon: /*#__PURE__*/ jsx(ActivityIcon, {
311
- width: 14,
312
- height: 14
313
- })
314
- }
315
- ];
316
- return /*#__PURE__*/ jsxs("div", {
317
- className: "ov-experience-dashboard__impact",
318
- children: [
319
- /*#__PURE__*/ jsxs("div", {
320
- className: "ov-experience-dashboard__heading",
119
+ children: options.map((option)=>{
120
+ const selected = option.id === data.selectedId;
121
+ const content = /*#__PURE__*/ jsxs(Fragment, {
321
122
  children: [
322
- /*#__PURE__*/ jsxs("div", {
323
- children: [
324
- /*#__PURE__*/ jsx("h2", {
325
- children: t.application
326
- }),
327
- /*#__PURE__*/ jsx("span", {
328
- children: t.notice
329
- })
330
- ]
123
+ option.icon && /*#__PURE__*/ jsx("span", {
124
+ className: "ov-scope-switcher__icon",
125
+ "aria-hidden": "true",
126
+ children: option.icon
331
127
  }),
332
- /*#__PURE__*/ jsxs("select", {
333
- "aria-label": t.range,
334
- value: days,
335
- onChange: (event)=>onDaysChange(Number(event.target.value)),
128
+ /*#__PURE__*/ jsxs("span", {
129
+ className: "ov-scope-switcher__option-text",
336
130
  children: [
337
- /*#__PURE__*/ jsx("option", {
338
- value: 7,
339
- children: t.week
340
- }),
341
- /*#__PURE__*/ jsx("option", {
342
- value: 30,
343
- children: t.month
344
- }),
345
- /*#__PURE__*/ jsx("option", {
346
- value: 0,
347
- children: t.all
348
- })
349
- ]
350
- })
351
- ]
352
- }),
353
- /*#__PURE__*/ jsx("dl", {
354
- className: "ov-experience-dashboard__metrics",
355
- children: metrics.map((metric)=>/*#__PURE__*/ jsxs("div", {
356
- title: void 0 === metric.value ? t.unsupportedMetric : void 0,
357
- children: [
358
- metric.icon,
359
- /*#__PURE__*/ jsx("dd", {
360
- children: metric.value ?? '—'
361
- }),
362
- /*#__PURE__*/ jsx("dt", {
363
- children: metric.label
364
- })
365
- ]
366
- }, metric.label))
367
- }),
368
- /*#__PURE__*/ jsx("section", {
369
- className: "ov-experience-dashboard__distribution",
370
- "aria-label": t.outcomes,
371
- children: data.outcomes?.length ? ORDER.map((outcome)=>{
372
- const count = data.outcomes?.find((item)=>item.outcome === outcome)?.count ?? 0;
373
- return /*#__PURE__*/ jsxs("div", {
374
- className: "ov-experience-dashboard__outcome",
375
- children: [
376
- /*#__PURE__*/ jsxs("div", {
377
- children: [
378
- /*#__PURE__*/ jsx("span", {
379
- children: t[outcome]
380
- }),
381
- /*#__PURE__*/ jsx("strong", {
382
- children: count
383
- })
384
- ]
385
- }),
386
- /*#__PURE__*/ jsx("div", {
387
- className: "ov-experience-dashboard__outcome-track",
388
- "aria-hidden": "true",
389
- children: /*#__PURE__*/ jsx("span", {
390
- style: {
391
- width: `${total > 0 ? Math.max(count / total * 100, count ? 2 : 0) : 0}%`
392
- }
131
+ /*#__PURE__*/ jsx("span", {
132
+ children: /*#__PURE__*/ jsx(Highlight, {
133
+ text: option.label,
134
+ keyword: keyword
393
135
  })
136
+ }),
137
+ option.description && /*#__PURE__*/ jsx("small", {
138
+ children: option.description
394
139
  })
395
140
  ]
396
- }, outcome);
397
- }) : /*#__PURE__*/ jsx(DashboardState, {
398
- state: outcomesState,
399
- empty: t.emptyOutcomes,
400
- loading: t.loading,
401
- failed: t.failed,
402
- retry: t.retry
403
- })
404
- }),
405
- /*#__PURE__*/ jsxs("section", {
406
- className: "ov-experience-dashboard__trajectories",
407
- children: [
408
- /*#__PURE__*/ jsxs("h3", {
409
- children: [
410
- t.trajectories,
411
- void 0 === data.trajectoryTotal ? '' : ` · ${data.trajectoryTotal}`
412
- ]
413
141
  }),
414
- data.trajectories?.length ? /*#__PURE__*/ jsx(ExperienceTrajectories, {
415
- items: data.trajectories,
416
- onOpenUri: onOpenUri
417
- }) : /*#__PURE__*/ jsx(DashboardState, {
418
- state: trajectoriesState,
419
- empty: t.empty,
420
- loading: t.loading,
421
- failed: t.failed,
422
- retry: t.retry
142
+ selected && /*#__PURE__*/ jsx("span", {
143
+ className: "ov-scope-switcher__check",
144
+ "aria-hidden": "true",
145
+ children: /*#__PURE__*/ jsx(checkreact, {})
423
146
  })
424
147
  ]
425
- })
426
- ]
427
- });
428
- }
429
- function CopyButton({ value, labels: t }) {
430
- const [result, setResult] = useState();
431
- const state = result?.value === value ? result.state : void 0;
432
- const copy = async ()=>{
433
- setResult({
434
- value,
435
- state: 'pending'
436
- });
437
- try {
438
- await navigator.clipboard.writeText(value);
439
- setResult({
440
- value,
441
- state: 'copied'
442
- });
443
- } catch {
444
- setResult({
445
- value,
446
- state: 'failed'
447
148
  });
448
- }
449
- };
450
- return /*#__PURE__*/ jsx("button", {
451
- type: "button",
452
- disabled: !value || 'pending' === state,
453
- "aria-live": "polite",
454
- onClick: ()=>void copy(),
455
- children: 'copied' === state ? t.copied : 'failed' === state ? t.copyFailed : t.copy
149
+ return /*#__PURE__*/ jsx("div", {
150
+ tabIndex: option.disabled || state?.busy ? -1 : 0,
151
+ role: "option",
152
+ "aria-selected": selected,
153
+ className: "ov-scope-switcher__option",
154
+ title: option.label,
155
+ "aria-disabled": option.disabled || state?.busy || void 0,
156
+ onClick: (event)=>{
157
+ const target = event.target;
158
+ if (option.disabled || state?.busy || target.closest('button, a, input, select, textarea, [role="button"]')) return;
159
+ onSelect(option);
160
+ },
161
+ onKeyDown: (event)=>{
162
+ if (event.target !== event.currentTarget || option.disabled || state?.busy) return;
163
+ if ('Enter' === event.key || ' ' === event.key) {
164
+ event.preventDefault();
165
+ onSelect(option);
166
+ }
167
+ },
168
+ children: slots?.renderOption ? slots?.renderOption(content, option) : content
169
+ }, option.id);
170
+ })
171
+ }, keyword) : /*#__PURE__*/ jsx("div", {
172
+ className: "ov-scope-switcher__state",
173
+ role: "status",
174
+ children: slots?.emptyFallback ?? (hasKeyword ? labels.noMatch : labels.empty)
456
175
  });
457
- }
458
- function ExperienceTests({ items, labels: t, onOpenUri }) {
459
176
  return /*#__PURE__*/ jsx("div", {
460
- className: "ov-experience-dashboard__tests",
461
- children: items.map((item)=>/*#__PURE__*/ jsxs("article", {
462
- children: [
463
- /*#__PURE__*/ jsxs("header", {
464
- children: [
465
- /*#__PURE__*/ jsxs("div", {
466
- className: "ov-experience-dashboard__test-heading",
467
- children: [
468
- /*#__PURE__*/ jsx("strong", {
469
- children: item.title
470
- }),
471
- /*#__PURE__*/ jsxs("div", {
472
- className: "ov-experience-dashboard__test-meta",
473
- children: [
474
- /*#__PURE__*/ jsx("span", {
475
- children: t.sourceUri
476
- }),
477
- /*#__PURE__*/ jsx("code", {
478
- title: item.uri,
479
- children: item.uri ?? '—'
480
- }),
481
- item.uri ? /*#__PURE__*/ jsxs(Fragment, {
482
- children: [
483
- /*#__PURE__*/ jsx(CopyButton, {
484
- value: item.uri,
485
- labels: t
486
- }),
487
- /*#__PURE__*/ jsx("button", {
488
- type: "button",
489
- disabled: !onOpenUri,
490
- onClick: ()=>item.uri && onOpenUri?.(item.uri),
491
- children: t.open
492
- })
493
- ]
494
- }) : null
495
- ]
496
- }),
497
- item.taskQuery ? /*#__PURE__*/ jsxs("div", {
498
- className: "ov-experience-dashboard__test-meta",
499
- children: [
500
- /*#__PURE__*/ jsx("span", {
501
- children: t.task
502
- }),
503
- /*#__PURE__*/ jsx("p", {
504
- children: item.taskQuery
505
- })
506
- ]
507
- }) : null
508
- ]
509
- }),
510
- /*#__PURE__*/ jsx(CopyButton, {
511
- value: item.content,
512
- labels: t
513
- })
514
- ]
515
- }),
516
- /*#__PURE__*/ jsx("div", {
517
- className: "ov-experience-dashboard__test-content",
518
- children: item.content.split('\n').map((line, index)=>{
519
- const role = line.match(/^(User|Assistant):(.*)$/);
520
- return /*#__PURE__*/ jsx("div", {
521
- children: role ? /*#__PURE__*/ jsxs(Fragment, {
522
- children: [
523
- /*#__PURE__*/ jsxs("strong", {
524
- children: [
525
- role[1],
526
- ":"
527
- ]
528
- }),
529
- role[2]
530
- ]
531
- }) : line.startsWith('# ') ? /*#__PURE__*/ jsx("strong", {
532
- children: line
533
- }) : line || '\u00a0'
534
- }, index);
535
- })
536
- })
537
- ]
538
- }, item.id))
177
+ role: "group",
178
+ tabIndex: -1,
179
+ ref: focusPanel,
180
+ className: "ov-scope-switcher__panel-inner",
181
+ onKeyDownCapture: moveScopeFocus,
182
+ children: slots?.renderPanel ? slots?.renderPanel({
183
+ search,
184
+ list
185
+ }) : /*#__PURE__*/ jsxs("div", {
186
+ className: "ov-scope-switcher__panel-body",
187
+ children: [
188
+ search,
189
+ list
190
+ ]
191
+ })
539
192
  });
540
193
  }
541
- function ExperiencePagination({ page, hasMore, loading, labels: t, onPageChange }) {
542
- if (!page && !hasMore) return null;
543
- return /*#__PURE__*/ jsxs("div", {
544
- className: "ov-experience-dashboard__pagination",
194
+ function ScopeSelector(props) {
195
+ const { identity, trigger: triggerContent } = props;
196
+ const locale = useLocale(props.locale);
197
+ const labels = resolveScopeLabels(locale, props.labels);
198
+ const selectable = 'selectable' === props.kind ? props : void 0;
199
+ const data = selectable?.data;
200
+ const state = selectable?.state;
201
+ const actions = selectable?.actions;
202
+ const slots = selectable?.slots;
203
+ const [localVisible, setLocalVisible] = useState(false);
204
+ const root = useRef(null);
205
+ const trigger = useRef(null);
206
+ const restoreSelectionFocus = useRef(false);
207
+ const panelId = useId();
208
+ const open = void 0 !== selectable && (state?.visible ?? localVisible) && !state?.disabled;
209
+ const onVisibleChange = actions?.onVisibleChange;
210
+ const changeVisible = useCallback((visible)=>{
211
+ setLocalVisible(visible);
212
+ onVisibleChange?.(visible);
213
+ }, [
214
+ onVisibleChange
215
+ ]);
216
+ useEffect(()=>{
217
+ if (!open) return;
218
+ const dismiss = (event)=>{
219
+ if (event.target instanceof Node && !root.current?.contains(event.target)) changeVisible(false);
220
+ };
221
+ const escape = (event)=>{
222
+ if ('Escape' === event.key) {
223
+ event.preventDefault();
224
+ changeVisible(false);
225
+ trigger.current?.focus();
226
+ }
227
+ };
228
+ document.addEventListener('pointerdown', dismiss);
229
+ document.addEventListener('keydown', escape);
230
+ return ()=>{
231
+ document.removeEventListener('pointerdown', dismiss);
232
+ document.removeEventListener('keydown', escape);
233
+ };
234
+ }, [
235
+ open,
236
+ changeVisible
237
+ ]);
238
+ useEffect(()=>{
239
+ if (open || !restoreSelectionFocus.current) return;
240
+ restoreSelectionFocus.current = false;
241
+ if (document.activeElement === document.body || root.current?.contains(document.activeElement)) trigger.current?.focus();
242
+ }, [
243
+ open
244
+ ]);
245
+ const selected = data?.options.find((o)=>o.id === data.selectedId);
246
+ const label = triggerContent?.label ?? selected?.label ?? '';
247
+ const icon = triggerContent?.icon ?? selected?.icon;
248
+ const content = /*#__PURE__*/ jsxs(Fragment, {
545
249
  children: [
546
- /*#__PURE__*/ jsx("button", {
547
- type: "button",
548
- disabled: !page || loading || !onPageChange,
549
- onClick: ()=>onPageChange?.(page - 1),
550
- children: t.previous
250
+ icon && /*#__PURE__*/ jsx("span", {
251
+ className: "ov-scope-switcher__icon",
252
+ "aria-hidden": "true",
253
+ children: icon
551
254
  }),
552
255
  /*#__PURE__*/ jsx("span", {
553
- children: page + 1
256
+ className: "ov-scope-switcher__label",
257
+ children: label
554
258
  }),
555
- /*#__PURE__*/ jsx("button", {
556
- type: "button",
557
- disabled: !hasMore || loading || !onPageChange,
558
- onClick: ()=>onPageChange?.(page + 1),
559
- children: t.next
259
+ identity.tag && /*#__PURE__*/ jsx("span", {
260
+ className: "ov-scope-switcher__tag",
261
+ children: identity.tag
560
262
  })
561
263
  ]
562
264
  });
563
- }
564
- function ExperienceDashboard(props) {
565
- return /*#__PURE__*/ jsx(ExperienceDashboardContent, {
566
- ...props
567
- }, props.uri);
568
- }
569
- function ExperienceDashboardContent({ uri, data = {}, kind, tab: controlledTab, days: controlledDays, page = 0, hasMore = false, startIndex = 0, states = {}, onTabChange, onDaysChange, onPageChange, locale: localeProp, onOpenUri, labels, className, ...rest }) {
570
- const locale = useLocale(localeProp);
571
- const [localTab, setLocalTab] = useState('impact');
572
- const [localDays, setLocalDays] = useState(7);
573
- const selectedTab = controlledTab ?? localTab;
574
- const missingTest = void 0 === data.testMaterials;
575
- const tab = 'test' === selectedTab && missingTest ? 'impact' : selectedTab;
576
- if ('test' === localTab && missingTest) setLocalTab('impact');
577
- const days = controlledDays ?? localDays;
578
- const setTab = (value)=>{
579
- setLocalTab(value);
580
- onTabChange?.(value);
581
- };
582
- const setDays = (value)=>{
583
- setLocalDays(value);
584
- onDaysChange?.(value);
585
- };
586
- const t = experienceLabels(locale, labels);
587
- const directory = 'directory' === kind;
588
- const result = data;
589
- const tabs = [
590
- {
591
- key: 'impact',
592
- title: t.impact
593
- },
594
- {
595
- key: 'source',
596
- title: t.source
265
+ return /*#__PURE__*/ jsxs("div", {
266
+ ref: root,
267
+ role: "group",
268
+ className: "ov-scope-switcher__level",
269
+ onBlur: (event)=>{
270
+ if (open && event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) changeVisible(false);
597
271
  },
598
- ...void 0 === result.testMaterials ? [] : [
599
- {
600
- key: 'test',
601
- title: t.test
602
- }
603
- ]
604
- ];
605
- const activeState = directory ? states.list : 'source' === tab ? states.sources : states.trajectories;
606
- const pagination = /*#__PURE__*/ jsx(ExperiencePagination, {
607
- page: page,
608
- hasMore: hasMore,
609
- loading: activeState?.loading,
610
- labels: t,
611
- onPageChange: onPageChange
612
- });
613
- return /*#__PURE__*/ jsx("div", {
614
- ...rest,
615
- "data-resource-uri": uri,
616
- className: [
617
- 'ov-experience-dashboard',
618
- className
619
- ].filter(Boolean).join(' '),
620
- children: directory ? /*#__PURE__*/ jsxs("div", {
621
- className: "ov-experience-dashboard__body",
622
- children: [
623
- result.experiences?.length ? /*#__PURE__*/ jsx(ExperienceList, {
624
- items: result.experiences,
625
- total: result.total,
626
- locale: locale,
627
- startIndex: startIndex,
628
- labels: t,
629
- onOpenUri: onOpenUri
630
- }) : /*#__PURE__*/ jsx(DashboardState, {
631
- state: states.list,
632
- empty: t.empty,
633
- loading: t.loading,
634
- failed: t.failed,
635
- retry: t.retry
636
- }),
637
- pagination
638
- ]
639
- }) : /*#__PURE__*/ jsx(DashboardTabs, {
640
- tabs: tabs,
641
- active: tab,
642
- label: t.title,
643
- onChange: setTab,
644
- children: /*#__PURE__*/ jsx("div", {
645
- className: "ov-experience-dashboard__body",
646
- children: 'impact' === tab ? /*#__PURE__*/ jsxs(Fragment, {
647
- children: [
648
- /*#__PURE__*/ jsx(ExperienceImpact, {
649
- data: result,
650
- labels: t,
651
- days: days,
652
- onDaysChange: setDays,
653
- outcomesState: states.outcomes ?? {},
654
- trajectoriesState: states.trajectories ?? {},
655
- onOpenUri: onOpenUri
656
- }),
657
- pagination
658
- ]
659
- }) : 'source' === tab ? result.sources?.length ? /*#__PURE__*/ jsxs("details", {
660
- open: true,
661
- className: "ov-experience-dashboard__source-group",
662
- children: [
663
- /*#__PURE__*/ jsxs("summary", {
664
- children: [
665
- /*#__PURE__*/ jsx("strong", {
666
- children: t.latest
667
- }),
668
- /*#__PURE__*/ jsx("span", {
669
- children: t.sourceCount.replace('{count}', String(result.sources.length))
670
- })
671
- ]
672
- }),
673
- /*#__PURE__*/ jsx(ExperienceTrajectories, {
674
- items: result.sources,
675
- source: true,
676
- onOpenUri: onOpenUri
677
- })
678
- ]
679
- }) : /*#__PURE__*/ jsx(DashboardState, {
680
- state: states.sources,
681
- empty: t.emptySource,
682
- loading: t.loading,
683
- failed: t.failed,
684
- retry: t.retry
685
- }) : result.testMaterials?.length ? /*#__PURE__*/ jsx(ExperienceTests, {
686
- items: result.testMaterials,
687
- labels: t,
688
- onOpenUri: onOpenUri
689
- }) : /*#__PURE__*/ jsx(DashboardState, {
690
- state: states.tests,
691
- empty: t.emptyTests,
692
- loading: t.loading,
693
- failed: t.failed,
694
- retry: t.retry
272
+ children: [
273
+ void 0 === selectable ? /*#__PURE__*/ jsx("span", {
274
+ className: "ov-scope-switcher__trigger",
275
+ "aria-label": identity.ariaLabel,
276
+ title: label,
277
+ children: content
278
+ }) : /*#__PURE__*/ jsxs("button", {
279
+ ref: trigger,
280
+ type: "button",
281
+ className: "ov-scope-switcher__trigger",
282
+ "aria-label": identity.ariaLabel,
283
+ title: label,
284
+ disabled: state?.disabled,
285
+ "aria-expanded": open,
286
+ "aria-haspopup": "dialog",
287
+ "aria-controls": open ? panelId : void 0,
288
+ onClick: ()=>changeVisible(!open),
289
+ onKeyDown: (event)=>{
290
+ if ('ArrowDown' === event.key || 'ArrowUp' === event.key) {
291
+ event.preventDefault();
292
+ if (open) root.current?.querySelector('[role="option"]:not([aria-disabled="true"])')?.focus();
293
+ else changeVisible(true);
294
+ }
295
+ },
296
+ children: [
297
+ content,
298
+ /*#__PURE__*/ jsx("span", {
299
+ className: "ov-scope-switcher__arrow",
300
+ "aria-hidden": "true",
301
+ children: /*#__PURE__*/ jsx(chevron_downreact, {})
302
+ })
303
+ ]
304
+ }),
305
+ open && void 0 !== selectable && void 0 !== data && /*#__PURE__*/ jsx("div", {
306
+ id: panelId,
307
+ className: slots?.renderPanel ? 'ov-scope-switcher__panel ov-scope-switcher__panel--custom' : 'ov-scope-switcher__panel',
308
+ role: "dialog",
309
+ "aria-label": identity.ariaLabel ?? label,
310
+ children: /*#__PURE__*/ jsx(ScopePanel, {
311
+ label: identity.ariaLabel ?? label,
312
+ data: data,
313
+ state: state,
314
+ slots: slots,
315
+ actions: actions,
316
+ onSelect: (option)=>{
317
+ restoreSelectionFocus.current = true;
318
+ changeVisible(false);
319
+ actions?.onSelect?.(option);
320
+ },
321
+ labels: labels
695
322
  })
696
323
  })
324
+ ]
325
+ });
326
+ }
327
+ function ScopeSwitcher({ locale: localeProp, children, className = '', ...props }) {
328
+ const locale = useLocale(localeProp);
329
+ return /*#__PURE__*/ jsx(LocaleProvider, {
330
+ locale: locale,
331
+ children: /*#__PURE__*/ jsx("div", {
332
+ lang: locale,
333
+ ...props,
334
+ className: `ov-scope-switcher ${className}`,
335
+ children: children
697
336
  })
698
337
  });
699
338
  }
700
- export { ExperienceDashboard };
339
+ export { ScopeSelector, ScopeSwitcher };