@senguoyun/dsh-arkme 0.1.59 → 0.1.61

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 (154) hide show
  1. package/cordis.patch.yml +6 -0
  2. package/docs/dsh-input-system-topic.md +7 -3
  3. package/docs/search-dsh-navigation.md +37 -0
  4. package/lib/client.js +5823 -3562
  5. package/lib/client.js.map +1 -1
  6. package/lib/harness-model-client.js +9 -0
  7. package/lib/harness-native-selection-client.js +1341 -0
  8. package/lib/harness-onboarding-client.js +64 -2
  9. package/lib/harness-session-client.js +39 -2
  10. package/lib/harness-sidebar-client.js +214 -23
  11. package/lib/index.js +114 -156
  12. package/lib/persistent-extension.js +1 -1
  13. package/lib/{persistent-runtime-ByM3JB3z.js → persistent-runtime-CXd9RuRR.js} +30263 -29553
  14. package/lib/sdk.js +9 -0
  15. package/lib/types/arkme-service.d.ts +7 -1
  16. package/lib/types/arkme-service.d.ts.map +1 -1
  17. package/lib/types/client/ArkmeCalendarSurface.d.ts +22 -1
  18. package/lib/types/client/ArkmeCalendarSurface.d.ts.map +1 -1
  19. package/lib/types/client/ArkmeChatMemberActions.d.ts +1 -1
  20. package/lib/types/client/ArkmeChatMemberActions.d.ts.map +1 -1
  21. package/lib/types/client/ArkmeDetailShell.d.ts +3 -1
  22. package/lib/types/client/ArkmeDetailShell.d.ts.map +1 -1
  23. package/lib/types/client/ArkmeDshMenu.d.ts +38 -0
  24. package/lib/types/client/ArkmeDshMenu.d.ts.map +1 -0
  25. package/lib/types/client/ArkmeFileViewer.d.ts +1 -0
  26. package/lib/types/client/ArkmeFileViewer.d.ts.map +1 -1
  27. package/lib/types/client/ArkmeGroupChatControls.d.ts +4 -0
  28. package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
  29. package/lib/types/client/ArkmeMessageActions.d.ts.map +1 -1
  30. package/lib/types/client/ArkmeNoteDetails.d.ts +2 -1
  31. package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
  32. package/lib/types/client/ArkmeProductNavigation.d.ts.map +1 -1
  33. package/lib/types/client/ArkmeRecordEditHistory.d.ts +10 -0
  34. package/lib/types/client/ArkmeRecordEditHistory.d.ts.map +1 -0
  35. package/lib/types/client/ArkmeRichContent.d.ts +2 -1
  36. package/lib/types/client/ArkmeRichContent.d.ts.map +1 -1
  37. package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
  38. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  39. package/lib/types/client/ArkmeSourceBreadcrumb.d.ts +6 -2
  40. package/lib/types/client/ArkmeSourceBreadcrumb.d.ts.map +1 -1
  41. package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts +5 -2
  42. package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts.map +1 -1
  43. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  44. package/lib/types/client/ArkmeWorldSurface.d.ts +3 -3
  45. package/lib/types/client/ArkmeWorldSurface.d.ts.map +1 -1
  46. package/lib/types/client/DeepSeekHarnessSurface.d.ts +4 -0
  47. package/lib/types/client/DeepSeekHarnessSurface.d.ts.map +1 -1
  48. package/lib/types/client/PrivateChatActions.d.ts +15 -3
  49. package/lib/types/client/PrivateChatActions.d.ts.map +1 -1
  50. package/lib/types/client/api.d.ts +1 -1
  51. package/lib/types/client/api.d.ts.map +1 -1
  52. package/lib/types/client/arkme-theme.d.ts +1 -0
  53. package/lib/types/client/arkme-theme.d.ts.map +1 -1
  54. package/lib/types/client/calendar-invalidation-store.d.ts +10 -1
  55. package/lib/types/client/calendar-invalidation-store.d.ts.map +1 -1
  56. package/lib/types/client/calendar-month-cache.d.ts +37 -0
  57. package/lib/types/client/calendar-month-cache.d.ts.map +1 -0
  58. package/lib/types/client/clipboard-text.d.ts +2 -0
  59. package/lib/types/client/clipboard-text.d.ts.map +1 -0
  60. package/lib/types/client/conversation-export.d.ts +18 -0
  61. package/lib/types/client/conversation-export.d.ts.map +1 -0
  62. package/lib/types/client/conversation-menu-layer.d.ts +27 -0
  63. package/lib/types/client/conversation-menu-layer.d.ts.map +1 -0
  64. package/lib/types/client/conversation-menu-scrollbars.d.ts +3 -0
  65. package/lib/types/client/conversation-menu-scrollbars.d.ts.map +1 -0
  66. package/lib/types/client/conversation-selector-style.d.ts +34 -0
  67. package/lib/types/client/conversation-selector-style.d.ts.map +1 -0
  68. package/lib/types/client/harness-native-selection-client.d.ts +13 -0
  69. package/lib/types/client/harness-native-selection-client.d.ts.map +1 -0
  70. package/lib/types/client/harness-native-selection-geometry.d.ts +47 -0
  71. package/lib/types/client/harness-native-selection-geometry.d.ts.map +1 -0
  72. package/lib/types/client/harness-native-selection-loader.d.ts +4 -0
  73. package/lib/types/client/harness-native-selection-loader.d.ts.map +1 -0
  74. package/lib/types/client/harness-native-selection.d.ts +35 -0
  75. package/lib/types/client/harness-native-selection.d.ts.map +1 -0
  76. package/lib/types/client/harness-onboarding-client.d.ts.map +1 -1
  77. package/lib/types/client/harness-session-client.d.ts.map +1 -1
  78. package/lib/types/client/harness-session-dropdown.d.ts.map +1 -1
  79. package/lib/types/client/harness-session-hover.d.ts +1 -1
  80. package/lib/types/client/harness-session-hover.d.ts.map +1 -1
  81. package/lib/types/client/harness-session-menu-bridge.d.ts +2 -0
  82. package/lib/types/client/harness-session-menu-bridge.d.ts.map +1 -1
  83. package/lib/types/client/harness-session-summary.d.ts +0 -7
  84. package/lib/types/client/harness-session-summary.d.ts.map +1 -1
  85. package/lib/types/client/harness-slots-contract.d.ts +12 -0
  86. package/lib/types/client/harness-slots-contract.d.ts.map +1 -0
  87. package/lib/types/client/harness-surface-viewport.d.ts +7 -0
  88. package/lib/types/client/harness-surface-viewport.d.ts.map +1 -0
  89. package/lib/types/client/index.d.ts.map +1 -1
  90. package/lib/types/client/interwoven-moments.d.ts.map +1 -1
  91. package/lib/types/client/member-records-loader.d.ts +10 -0
  92. package/lib/types/client/member-records-loader.d.ts.map +1 -0
  93. package/lib/types/client/member-records-viewport.d.ts +10 -0
  94. package/lib/types/client/member-records-viewport.d.ts.map +1 -0
  95. package/lib/types/client/message-selection-presentation.d.ts +42 -2
  96. package/lib/types/client/message-selection-presentation.d.ts.map +1 -1
  97. package/lib/types/client/navigation-cache.d.ts +6 -1
  98. package/lib/types/client/navigation-cache.d.ts.map +1 -1
  99. package/lib/types/client/provider-instance-runtime.d.ts.map +1 -1
  100. package/lib/types/client/realtime-client-events.d.ts.map +1 -1
  101. package/lib/types/client/redesign/contacts/ContactProfileDetail.d.ts.map +1 -1
  102. package/lib/types/client/redesign/contacts/ContactWorldList.d.ts +2 -1
  103. package/lib/types/client/redesign/contacts/ContactWorldList.d.ts.map +1 -1
  104. package/lib/types/client/self-topic-directory-cache.d.ts +42 -0
  105. package/lib/types/client/self-topic-directory-cache.d.ts.map +1 -0
  106. package/lib/types/client/self-topic-expansion-preference.d.ts +23 -0
  107. package/lib/types/client/self-topic-expansion-preference.d.ts.map +1 -0
  108. package/lib/types/client/self-topic-menu-bridge.d.ts +20 -0
  109. package/lib/types/client/self-topic-menu-bridge.d.ts.map +1 -0
  110. package/lib/types/client/self-topic-menu-hover.d.ts +3 -0
  111. package/lib/types/client/self-topic-menu-hover.d.ts.map +1 -0
  112. package/lib/types/client/timeline-message-order.d.ts +4 -0
  113. package/lib/types/client/timeline-message-order.d.ts.map +1 -0
  114. package/lib/types/client/ui-controller.d.ts +7 -1
  115. package/lib/types/client/ui-controller.d.ts.map +1 -1
  116. package/lib/types/client/use-calendar-month.d.ts +4 -0
  117. package/lib/types/client/use-calendar-month.d.ts.map +1 -0
  118. package/lib/types/dsh-agent-input-source.d.ts +2 -0
  119. package/lib/types/dsh-agent-input-source.d.ts.map +1 -1
  120. package/lib/types/dsh-search-origins.d.ts +4 -0
  121. package/lib/types/dsh-search-origins.d.ts.map +1 -0
  122. package/lib/types/harness-embed-contract.d.ts +10 -0
  123. package/lib/types/harness-embed-contract.d.ts.map +1 -1
  124. package/lib/types/harness-embed-route.d.ts +2 -1
  125. package/lib/types/harness-embed-route.d.ts.map +1 -1
  126. package/lib/types/host-api.d.ts.map +1 -1
  127. package/lib/types/index.d.ts.map +1 -1
  128. package/lib/types/managed-ai/adapter.d.ts.map +1 -1
  129. package/lib/types/managed-ai/transport.d.ts.map +1 -1
  130. package/lib/types/record-edit-history.d.ts +21 -0
  131. package/lib/types/record-edit-history.d.ts.map +1 -0
  132. package/lib/types/sdk/index.d.ts +7 -0
  133. package/lib/types/sdk/index.d.ts.map +1 -1
  134. package/lib/types/services/calendar-service.d.ts +10 -0
  135. package/lib/types/services/calendar-service.d.ts.map +1 -1
  136. package/lib/types/services/chat-realtime-service.d.ts +3 -1
  137. package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
  138. package/lib/types/services/chat-service.d.ts +5 -1
  139. package/lib/types/services/chat-service.d.ts.map +1 -1
  140. package/lib/types/services/contact-directory-service.d.ts.map +1 -1
  141. package/lib/types/services/media-service.d.ts +7 -0
  142. package/lib/types/services/media-service.d.ts.map +1 -1
  143. package/lib/types/services/record-edit-history-service.d.ts +25 -0
  144. package/lib/types/services/record-edit-history-service.d.ts.map +1 -0
  145. package/lib/types/services/record-service.d.ts.map +1 -1
  146. package/lib/types/services/search-service.d.ts +1 -0
  147. package/lib/types/services/search-service.d.ts.map +1 -1
  148. package/lib/types/services/service.d.ts +5 -0
  149. package/lib/types/services/service.d.ts.map +1 -1
  150. package/lib/types/services/source-service.d.ts +3 -0
  151. package/lib/types/services/source-service.d.ts.map +1 -1
  152. package/lib/types/types.d.ts +21 -3
  153. package/lib/types/types.d.ts.map +1 -1
  154. package/package.json +5 -5
@@ -0,0 +1,1341 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@senguoyun/dsh-arkme/harness-native-selection",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
29
+ let react = require("react");
30
+ react = __toESM(react, 1);
31
+ let react_dom = require("react-dom");
32
+ let react_jsx_runtime = require("react/jsx-runtime");
33
+ //#region src/client/clipboard-text.ts
34
+ async function copyText(value, doc = document) {
35
+ if (doc.defaultView?.navigator.clipboard?.writeText !== void 0) try {
36
+ await doc.defaultView.navigator.clipboard.writeText(value);
37
+ return;
38
+ } catch {}
39
+ const textarea = doc.createElement("textarea");
40
+ textarea.value = value;
41
+ textarea.setAttribute("readonly", "true");
42
+ textarea.style.position = "fixed";
43
+ textarea.style.left = "-9999px";
44
+ textarea.style.top = "0";
45
+ doc.body.appendChild(textarea);
46
+ const selection = doc.getSelection();
47
+ const activeElement = doc.activeElement instanceof doc.defaultView.HTMLElement ? doc.activeElement : void 0;
48
+ try {
49
+ textarea.select();
50
+ if (!doc.execCommand("copy")) throw new Error("复制失败,请稍后重试");
51
+ } finally {
52
+ textarea.remove();
53
+ selection?.removeAllRanges();
54
+ if (activeElement?.isConnected) activeElement.focus();
55
+ }
56
+ }
57
+ //#endregion
58
+ //#region node_modules/@phosphor-icons/react/dist/lib/context.es.js
59
+ const o = (0, react.createContext)({
60
+ color: "currentColor",
61
+ size: "1em",
62
+ weight: "regular",
63
+ mirrored: !1
64
+ });
65
+ //#endregion
66
+ //#region node_modules/@phosphor-icons/react/dist/lib/IconBase.es.js
67
+ const p = react.forwardRef((s, a) => {
68
+ const { alt: n, color: r, size: t, weight: o$1, mirrored: c, children: i, weights: m, ...x } = s, { color: d = "currentColor", size: l, weight: f = "regular", mirrored: g = !1, ...w } = react.useContext(o);
69
+ return /* @__PURE__ */ react.createElement("svg", {
70
+ ref: a,
71
+ xmlns: "http://www.w3.org/2000/svg",
72
+ width: t != null ? t : l,
73
+ height: t != null ? t : l,
74
+ fill: r != null ? r : d,
75
+ viewBox: "0 0 256 256",
76
+ transform: c || g ? "scale(-1, 1)" : void 0,
77
+ ...w,
78
+ ...x
79
+ }, !!n && /* @__PURE__ */ react.createElement("title", null, n), i, m.get(o$1 != null ? o$1 : f));
80
+ });
81
+ p.displayName = "IconBase";
82
+ //#endregion
83
+ //#region node_modules/@phosphor-icons/react/dist/defs/X.es.js
84
+ const a = /* @__PURE__ */ new Map([
85
+ ["bold", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208.49,191.51a12,12,0,0,1-17,17L128,145,64.49,208.49a12,12,0,0,1-17-17L111,128,47.51,64.49a12,12,0,0,1,17-17L128,111l63.51-63.52a12,12,0,0,1,17,17L145,128Z" }))],
86
+ ["duotone", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", {
87
+ d: "M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z",
88
+ opacity: "0.2"
89
+ }), /* @__PURE__ */ react.createElement("path", { d: "M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z" }))],
90
+ ["fill", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM181.66,170.34a8,8,0,0,1-11.32,11.32L128,139.31,85.66,181.66a8,8,0,0,1-11.32-11.32L116.69,128,74.34,85.66A8,8,0,0,1,85.66,74.34L128,116.69l42.34-42.35a8,8,0,0,1,11.32,11.32L139.31,128Z" }))],
91
+ ["light", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M204.24,195.76a6,6,0,1,1-8.48,8.48L128,136.49,60.24,204.24a6,6,0,0,1-8.48-8.48L119.51,128,51.76,60.24a6,6,0,0,1,8.48-8.48L128,119.51l67.76-67.75a6,6,0,0,1,8.48,8.48L136.49,128Z" }))],
92
+ ["regular", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z" }))],
93
+ ["thin", /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("path", { d: "M202.83,197.17a4,4,0,0,1-5.66,5.66L128,133.66,58.83,202.83a4,4,0,0,1-5.66-5.66L122.34,128,53.17,58.83a4,4,0,0,1,5.66-5.66L128,122.34l69.17-69.17a4,4,0,1,1,5.66,5.66L133.66,128Z" }))]
94
+ ]);
95
+ //#endregion
96
+ //#region node_modules/@phosphor-icons/react/dist/csr/X.es.js
97
+ const e = react.forwardRef((r, t) => /* @__PURE__ */ react.createElement(p, {
98
+ ref: t,
99
+ ...r,
100
+ weights: a
101
+ }));
102
+ e.displayName = "XIcon";
103
+ const n = e;
104
+ //#endregion
105
+ //#region src/client/arkme-theme.ts
106
+ /**
107
+ * Arkme semantic colors. DSH owns the active light/dark/system preference and
108
+ * swaps every referenced token when `data-ds-dark-theme` changes on `<body>`.
109
+ * Arkme deliberately has no second theme store or independent toggle.
110
+ */
111
+ const arkmeTheme = {
112
+ base: "var(--dsw-alias-bg-base, #ffffff)",
113
+ layer1: "var(--dsw-alias-bg-layer-1, #f8f9fa)",
114
+ layer2: "var(--dsw-alias-bg-layer-2, #f3f4f6)",
115
+ layer3: "var(--dsw-alias-bg-layer-3, #ffffff)",
116
+ sidebar: "var(--dsw-specific-sidebar-fill, var(--dsw-alias-bg-layer-1, #f8f9fa))",
117
+ input: "var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-2, #ffffff))",
118
+ menu: "var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #ffffff))",
119
+ messageOwn: "var(--arkme-chat-self-bubble, var(--dsw-alias-state-business-tertiary, #eef1f8))",
120
+ messageOther: "var(--arkme-chat-other-bubble, var(--dsw-specific-bubble, var(--dsw-alias-bg-layer-2, #f3f4f6)))",
121
+ memberRecordOther: "var(--arkme-member-record-other-bubble, var(--dsw-specific-bubble-highlight, var(--dsw-alias-bg-layer-3, #e1e5ee)))",
122
+ subtle: "var(--dsw-alias-bg-module-platform, var(--dsw-alias-bg-layer-1, #f5f6f8))",
123
+ extensionSource: "var(--dsw-alias-fill-secondary, var(--dsw-alias-bg-module-platform, #f2f2f2))",
124
+ elevated: "var(--dsw-alias-button-elevated-fill, var(--dsw-alias-bg-layer-2, #ffffff))",
125
+ primaryAction: "var(--dsw-alias-button-primary-fill, #17191c)",
126
+ onPrimaryAction: "var(--dsw-alias-label-primary-inverted, #ffffff)",
127
+ hover: "var(--dsw-alias-interactive-bg-hover, rgba(38, 49, 72, 0.06))",
128
+ active: "var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.10))",
129
+ text: "var(--dsw-alias-label-primary, #17191c)",
130
+ secondary: "var(--dsw-alias-label-secondary, #68707c)",
131
+ tertiary: "var(--dsw-alias-label-tertiary, #9097a1)",
132
+ caption: "var(--dsw-alias-label-caption, #a3a8ae)",
133
+ foreground: "var(--dsw-static-neutral-bluish-00, #ffffff)",
134
+ border: "var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.10))",
135
+ borderSoft: "var(--dsw-alias-border-l1, rgba(0, 0, 0, 0.04))",
136
+ accent: "var(--dsw-alias-state-business-primary, #8295e8)",
137
+ accentSoft: "var(--dsw-alias-state-business-tertiary, #f1f2f6)",
138
+ info: "var(--dsw-alias-state-business-primary, #3964fe)",
139
+ infoSoft: "var(--dsw-alias-state-business-tertiary, #e9f0ff)",
140
+ success: "var(--dsw-alias-state-success-primary, #52c41a)",
141
+ danger: "var(--dsw-alias-state-error-primary, #c2413b)",
142
+ dangerSoft: "var(--dsw-alias-interactive-bg-hover-danger, rgba(194, 65, 59, 0.10))",
143
+ warning: "var(--dsw-alias-state-warn-label, #a16207)",
144
+ recordHistoryLatest: "#edbe09",
145
+ warningSoft: "var(--dsw-alias-state-warn-tertiary, #fff8e6)",
146
+ shadow: "var(--dsw-shadow-lv2, 0 4px 16px rgba(0, 0, 0, 0.12))"
147
+ };
148
+ //#endregion
149
+ //#region src/client/message-selection-presentation.tsx
150
+ const ARKME_MESSAGE_SELECT_HIT_SIZE = 32;
151
+ const ARKME_MESSAGE_SELECT_GAP = 10;
152
+ const ARKME_MESSAGE_SELECT_AVATAR_OFFSET = 1;
153
+ const ARKME_MESSAGE_SELECT_CARD_RAIL_SIZE = 42;
154
+ const messageSelectionStyles = {
155
+ rowSelectAvatarMode: {
156
+ display: "grid",
157
+ gridTemplateColumns: `${ARKME_MESSAGE_SELECT_HIT_SIZE}px minmax(0, 1fr)`,
158
+ alignItems: "start",
159
+ columnGap: ARKME_MESSAGE_SELECT_GAP,
160
+ marginBottom: 18,
161
+ paddingLeft: 6,
162
+ boxSizing: "border-box",
163
+ cursor: "pointer"
164
+ },
165
+ rowSelectCardCenterMode: {
166
+ display: "grid",
167
+ gridTemplateColumns: `${ARKME_MESSAGE_SELECT_CARD_RAIL_SIZE}px minmax(0, 1fr) ${ARKME_MESSAGE_SELECT_CARD_RAIL_SIZE}px`,
168
+ alignItems: "center",
169
+ marginBottom: 42,
170
+ cursor: "pointer"
171
+ },
172
+ rowSelectedForAction: { background: arkmeTheme.active },
173
+ selectCheck: {
174
+ width: ARKME_MESSAGE_SELECT_HIT_SIZE,
175
+ height: ARKME_MESSAGE_SELECT_HIT_SIZE,
176
+ display: "grid",
177
+ placeItems: "center",
178
+ border: 0,
179
+ padding: 0,
180
+ borderRadius: 999,
181
+ background: "transparent",
182
+ color: arkmeTheme.foreground,
183
+ cursor: "pointer"
184
+ },
185
+ selectCheckAvatar: {
186
+ justifySelf: "center",
187
+ marginTop: ARKME_MESSAGE_SELECT_AVATAR_OFFSET
188
+ },
189
+ selectCheckCardCenter: { justifySelf: "center" },
190
+ selectCheckCircle: {
191
+ width: 22,
192
+ height: 22,
193
+ display: "grid",
194
+ placeItems: "center",
195
+ boxSizing: "border-box",
196
+ borderWidth: 1.5,
197
+ borderStyle: "solid",
198
+ borderColor: arkmeTheme.tertiary,
199
+ borderRadius: 999,
200
+ background: "transparent",
201
+ color: arkmeTheme.foreground
202
+ },
203
+ selectCheckActive: {
204
+ borderColor: arkmeTheme.accent,
205
+ background: arkmeTheme.accent
206
+ },
207
+ selectBar: {
208
+ flex: "none",
209
+ minHeight: 72,
210
+ display: "flex",
211
+ alignItems: "center",
212
+ justifyContent: "center",
213
+ gap: "clamp(6px, 1.7vw, 18px)",
214
+ padding: "7px clamp(8px, 3vw, 16px)",
215
+ boxSizing: "border-box",
216
+ borderTop: `1px solid ${arkmeTheme.border}`,
217
+ background: arkmeTheme.layer2
218
+ },
219
+ selectBarButton: {
220
+ width: "clamp(44px, 6vw, 54px)",
221
+ minWidth: 0,
222
+ flex: "none",
223
+ display: "flex",
224
+ flexDirection: "column",
225
+ alignItems: "center",
226
+ gap: 5,
227
+ border: 0,
228
+ padding: 0,
229
+ background: "transparent",
230
+ color: arkmeTheme.text,
231
+ cursor: "pointer",
232
+ fontSize: 11
233
+ },
234
+ selectBarButtonDisabled: {
235
+ opacity: .38,
236
+ cursor: "default"
237
+ },
238
+ selectBarIconTile: {
239
+ width: "clamp(30px, 3.8vw, 34px)",
240
+ height: "clamp(30px, 3.8vw, 34px)",
241
+ display: "grid",
242
+ placeItems: "center",
243
+ borderRadius: 7,
244
+ background: arkmeTheme.elevated,
245
+ color: arkmeTheme.text,
246
+ boxShadow: "none"
247
+ },
248
+ selectBarLabel: {
249
+ lineHeight: "15px",
250
+ whiteSpace: "nowrap"
251
+ }
252
+ };
253
+ function ArkmeMessageSelectionControl(props) {
254
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
255
+ type: "button",
256
+ role: "checkbox",
257
+ "data-arkme-select-check": "true",
258
+ "data-arkme-selection-anchor": props.anchor,
259
+ "aria-checked": props.checked,
260
+ "aria-label": props.checked ? "取消选择消息" : "选择消息",
261
+ disabled: props.disabled,
262
+ style: {
263
+ ...messageSelectionStyles.selectCheck,
264
+ ...props.anchor === "avatar" ? messageSelectionStyles.selectCheckAvatar : messageSelectionStyles.selectCheckCardCenter,
265
+ opacity: props.disabled ? .35 : 1
266
+ },
267
+ onClick: (event) => {
268
+ event.stopPropagation();
269
+ props.onToggle();
270
+ },
271
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
272
+ style: {
273
+ ...messageSelectionStyles.selectCheckCircle,
274
+ ...props.checked ? messageSelectionStyles.selectCheckActive : {}
275
+ },
276
+ children: props.checked ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
277
+ "aria-hidden": true,
278
+ width: "14",
279
+ height: "14",
280
+ viewBox: "0 0 14 14",
281
+ fill: "none",
282
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
283
+ d: "M3.08 7.08L5.9 9.82L10.92 4.18",
284
+ stroke: "currentColor",
285
+ strokeWidth: "1.8",
286
+ strokeLinecap: "round",
287
+ strokeLinejoin: "round"
288
+ })
289
+ }) : null
290
+ })
291
+ });
292
+ }
293
+ function ArkmeSelectActionIcon({ kind, size = 22 }) {
294
+ if (kind === "assign") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
295
+ width: size,
296
+ height: size,
297
+ viewBox: "0 0 20 20",
298
+ fill: "none",
299
+ "aria-hidden": true,
300
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
301
+ fillRule: "evenodd",
302
+ clipRule: "evenodd",
303
+ d: "M12.6 2.5H7.4C6.25514 2.5 5.48671 2.50117 4.89496 2.54952C4.32071 2.59643 4.04615 2.6802 3.86502 2.77248C3.39462 3.01217 3.01217 3.39462 2.77248 3.86502C2.6802 4.04615 2.59643 4.32071 2.54952 4.89496C2.50117 5.48671 2.5 6.25514 2.5 7.4V15.8754C2.5 16.283 2.50033 16.5407 2.50855 16.7322C2.5139 16.8568 2.52154 16.9115 2.52348 16.9248C2.59801 17.1596 2.83292 17.3052 3.07637 17.2675C3.08914 17.2633 3.14151 17.2459 3.25551 17.1952C3.43068 17.1174 3.66164 17.003 4.02666 16.8217L4.05608 16.8071C4.20179 16.7347 4.33028 16.6708 4.46463 16.6145C4.92599 16.4211 5.41636 16.306 5.91557 16.274C6.06095 16.2646 6.20444 16.2647 6.36718 16.2647L6.4 16.2647H9.04451C9.10561 16.7861 9.22841 17.2886 9.40541 17.7647H6.4C6.2052 17.7647 6.1078 17.7647 6.01173 17.7709C5.67893 17.7923 5.35201 17.869 5.04444 17.9979C4.95566 18.0351 4.86843 18.0784 4.69396 18.1651C3.98787 18.5158 3.63482 18.6912 3.35471 18.7417C2.34708 18.9233 1.36504 18.3145 1.07941 17.3313C1 17.058 1 16.6638 1 15.8754V7.4C1 5.15979 1 4.03969 1.43597 3.18404C1.81947 2.43139 2.43139 1.81947 3.18404 1.43597C4.03969 1 5.15979 1 7.4 1H12.6C14.8402 1 15.9603 1 16.816 1.43597C17.5686 1.81947 18.1805 2.43139 18.564 3.18404C19 4.03969 19 5.15979 19 7.4V10.0218C18.5368 9.72526 18.0335 9.48584 17.5 9.3135V7.4C17.5 6.25514 17.4988 5.48671 17.4505 4.89496C17.4036 4.32071 17.3198 4.04615 17.2275 3.86502C16.9878 3.39462 16.6054 3.01217 16.135 2.77248C15.9539 2.6802 15.6793 2.59643 15.105 2.54952C14.5133 2.50117 13.7449 2.5 12.6 2.5ZM10.75 11.0629V7.75H12C12.4142 7.75 12.75 7.41421 12.75 7C12.75 6.58579 12.4142 6.25 12 6.25H10H8C7.58579 6.25 7.25 6.58579 7.25 7C7.25 7.41421 7.58579 7.75 8 7.75H9.25V12.5C9.25 12.7128 9.33865 12.905 9.48104 13.0415C9.78235 12.3046 10.215 11.6353 10.75 11.0629Z",
304
+ fill: "currentColor"
305
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
306
+ d: "M15 18.5V12.5M15 12.5L13 14M15 12.5L17 14",
307
+ stroke: "currentColor",
308
+ strokeWidth: "1.5",
309
+ strokeLinecap: "round",
310
+ strokeLinejoin: "round"
311
+ })]
312
+ });
313
+ if (kind === "copy") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
314
+ width: size,
315
+ height: size,
316
+ viewBox: "0 0 20 20",
317
+ fill: "none",
318
+ "aria-hidden": true,
319
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
320
+ d: "M12.4998 0.916504C13.3618 0.916504 14.1884 1.25891 14.7979 1.86841C15.4074 2.4779 15.7498 3.30455 15.7498 4.1665V4.24984H15.8332C16.6772 4.24984 17.4882 4.57822 18.0944 5.1655C18.7007 5.75278 19.0547 6.55287 19.0815 7.3965L19.0832 7.49984V15.8332C19.0832 16.6772 18.7548 17.4882 18.1675 18.0944C17.5802 18.7007 16.7801 19.0547 15.9365 19.0815L15.8332 19.0832H7.49984C6.65578 19.0832 5.84483 18.7548 5.23858 18.1675C4.63233 17.5802 4.27834 16.7801 4.2515 15.9365L4.24984 15.8332V15.7498H4.1665C3.32245 15.7498 2.5115 15.4214 1.90525 14.8342C1.299 14.2469 0.945007 13.4468 0.918171 12.6032L0.916504 12.4998V4.1665C0.916504 3.30455 1.25891 2.4779 1.86841 1.86841C2.4779 1.25891 3.30455 0.916504 4.1665 0.916504H12.4998ZM15.7498 12.4998C15.7498 13.3618 15.4074 14.1884 14.7979 14.7979C14.1884 15.4074 13.3618 15.7498 12.4998 15.7498H5.74984V15.8332C5.74981 16.2822 5.92236 16.714 6.23181 17.0393C6.54125 17.3647 6.9639 17.5586 7.41234 17.5811L7.49984 17.5832H15.8332C16.2822 17.5832 16.714 17.4106 17.0393 17.1012C17.3647 16.7918 17.5586 16.3691 17.5811 15.9207L17.5832 15.8332V7.49984C17.5832 7.05084 17.4106 6.61901 17.1012 6.29367C16.7918 5.96833 16.3691 5.77437 15.9207 5.75192L15.8332 5.74984H15.7498V12.4998ZM12.4998 2.4165H4.1665C3.70237 2.4165 3.25726 2.60088 2.92907 2.92907C2.60088 3.25726 2.4165 3.70237 2.4165 4.1665V12.4998C2.4165 12.7297 2.46177 12.9572 2.54971 13.1695C2.63766 13.3819 2.76656 13.5748 2.92907 13.7373C3.09157 13.8998 3.28449 14.0287 3.49681 14.1166C3.70913 14.2046 3.93669 14.2498 4.1665 14.2498H12.4998C12.7297 14.2498 12.9572 14.2046 13.1695 14.1166C13.3819 14.0287 13.5748 13.8998 13.7373 13.7373C13.8998 13.5748 14.0287 13.3819 14.1166 13.1695C14.2046 12.9572 14.2498 12.7297 14.2498 12.4998V4.1665C14.2498 3.93669 14.2046 3.70913 14.1166 3.49681C14.0287 3.28449 13.8998 3.09157 13.7373 2.92907C13.5748 2.76656 13.3819 2.63766 13.1695 2.54971C12.9572 2.46177 12.7297 2.4165 12.4998 2.4165Z",
321
+ fill: "currentColor"
322
+ })
323
+ });
324
+ if (kind === "link") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
325
+ width: size,
326
+ height: size,
327
+ viewBox: "0 0 24 24",
328
+ fill: "none",
329
+ "aria-hidden": true,
330
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
331
+ d: "M13.06 10.9399C15.31 13.1899 15.31 16.8299 13.06 19.0699C10.81 21.3099 7.17003 21.3199 4.93003 19.0699C2.69003 16.8199 2.68003 13.1799 4.93003 10.9399",
332
+ stroke: "currentColor",
333
+ strokeWidth: "1.5",
334
+ strokeLinecap: "round",
335
+ strokeLinejoin: "round"
336
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
337
+ d: "M10.59 13.41C8.25002 11.07 8.25002 7.27001 10.59 4.92001C12.93 2.57001 16.73 2.58001 19.08 4.92001C21.43 7.26001 21.42 11.06 19.08 13.41",
338
+ stroke: "currentColor",
339
+ strokeWidth: "1.5",
340
+ strokeLinecap: "round",
341
+ strokeLinejoin: "round"
342
+ })]
343
+ });
344
+ if (kind === "select") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
345
+ width: size,
346
+ height: size,
347
+ viewBox: "0 0 20 20",
348
+ fill: "none",
349
+ "aria-hidden": true,
350
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
351
+ fillRule: "evenodd",
352
+ clipRule: "evenodd",
353
+ d: "M2.58997 5.26183C2.77832 5.45018 3.0236 5.54435 3.27108 5.54435C3.51855 5.54435 3.76603 5.45018 3.95437 5.26183L6.56929 2.64473C6.94598 2.26804 6.94598 1.6592 6.56929 1.28252C6.1926 0.905828 5.58377 0.905828 5.20708 1.28252L3.27108 3.21852L2.64473 2.59216C2.26804 2.21548 1.6592 2.21548 1.28252 2.59216C0.905828 2.96885 0.905828 3.57769 1.28252 3.95437L2.58997 5.26183ZM2.58997 11.9897C2.76956 12.1714 3.01484 12.2722 3.27108 12.2722C3.52731 12.2722 3.7726 12.1714 3.95218 11.9897L6.56929 9.37255C6.94598 8.99586 6.94598 8.38703 6.56929 8.01034C6.1926 7.63365 5.58377 7.63365 5.20708 8.01034L3.27108 9.94634L2.64473 9.31999C2.26804 8.9433 1.6592 8.9433 1.28252 9.31999C0.905828 9.69668 0.905828 10.3055 1.28252 10.6822L2.58997 11.9897ZM2.58997 18.7175C2.76956 18.8993 3.01484 19 3.27108 19C3.52731 19 3.7726 18.8993 3.95218 18.7175L6.56929 16.1004C6.94598 15.7237 6.94598 15.1149 6.56929 14.7382C6.1926 14.3615 5.58377 14.3615 5.20708 14.7382L3.27108 16.6742L2.64473 16.0478C2.26804 15.6711 1.6592 15.6711 1.28252 16.0478C0.905828 16.4245 0.905828 17.0333 1.28252 17.41L2.58997 18.7175ZM9.98566 18H18.0143C18.5587 18 19 17.5513 19 16.9977C19 16.4442 18.5587 15.9954 18.0143 15.9954H9.98566C9.44131 15.9954 9 16.4442 9 16.9977C9 17.5513 9.44131 18 9.98566 18ZM9.98566 4.00456H18.0143C18.5587 4.00456 19 3.55581 19 3.00228C19 2.44875 18.5587 2 18.0143 2H9.98566C9.44131 2 9 2.44875 9 3.00228C9 3.55581 9.44131 4.00456 9.98566 4.00456ZM9.98566 11.0023H18.0143C18.5587 11.0023 19 10.5535 19 10C19 9.44647 18.5587 8.99772 18.0143 8.99772H9.98566C9.44131 8.99772 9 9.44647 9 10C9 10.5535 9.44131 11.0023 9.98566 11.0023Z",
354
+ fill: "currentColor"
355
+ })
356
+ });
357
+ if (kind === "forward") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
358
+ width: size,
359
+ height: size,
360
+ viewBox: "0 0 24 24",
361
+ fill: "none",
362
+ "aria-hidden": true,
363
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
364
+ d: "M7.39993 6.31991L15.8899 3.48991C19.6999 2.21991 21.7699 4.29991 20.5099 8.10991L17.6799 16.5999C15.7799 22.3099 12.6599 22.3099 10.7599 16.5999L9.91993 14.0799L7.39993 13.2399C1.68993 11.3399 1.68993 8.22991 7.39993 6.31991Z",
365
+ stroke: "currentColor",
366
+ strokeWidth: "1.5",
367
+ strokeLinecap: "round",
368
+ strokeLinejoin: "round"
369
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
370
+ d: "M10.1101 13.6501L13.6901 10.0601",
371
+ stroke: "currentColor",
372
+ strokeWidth: "1.5",
373
+ strokeLinecap: "round",
374
+ strokeLinejoin: "round"
375
+ })]
376
+ });
377
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(n, {
378
+ size,
379
+ weight: "regular",
380
+ "aria-hidden": true
381
+ });
382
+ }
383
+ const messageSelectionMenuStyles = {
384
+ menu: {
385
+ position: "fixed",
386
+ zIndex: 1700,
387
+ width: 178,
388
+ padding: 6,
389
+ boxSizing: "border-box",
390
+ borderRadius: 10,
391
+ border: `1px solid ${arkmeTheme.border}`,
392
+ background: arkmeTheme.menu,
393
+ boxShadow: "0 14px 36px rgba(20,23,31,.16)"
394
+ },
395
+ menuButton: {
396
+ width: "100%",
397
+ minHeight: 34,
398
+ display: "flex",
399
+ alignItems: "center",
400
+ gap: 10,
401
+ padding: "8px 10px",
402
+ boxSizing: "border-box",
403
+ border: 0,
404
+ borderRadius: 8,
405
+ background: "transparent",
406
+ color: arkmeTheme.text,
407
+ cursor: "pointer",
408
+ font: "inherit",
409
+ fontSize: 13,
410
+ textAlign: "left"
411
+ },
412
+ menuIcon: {
413
+ width: 18,
414
+ flex: "none",
415
+ display: "inline-flex",
416
+ alignItems: "center",
417
+ justifyContent: "center",
418
+ color: arkmeTheme.secondary
419
+ }
420
+ };
421
+ //#endregion
422
+ //#region src/client/harness-native-selection.ts
423
+ const EMPTY_NATIVE_SELECTION = {
424
+ active: false,
425
+ keys: /* @__PURE__ */ new Set()
426
+ };
427
+ /** Pure session-local selection rules; React owns subscription and lifetime. */
428
+ function nativeSelectionReducer(state, action) {
429
+ if (action.type === "exit") return state.active ? EMPTY_NATIVE_SELECTION : state;
430
+ if (action.type === "enter") return state.active ? state : {
431
+ active: true,
432
+ keys: new Set(action.key ? [action.key] : [])
433
+ };
434
+ if (!state.active || action.type === "remove" && !state.keys.has(action.key)) return state;
435
+ const keys = new Set(state.keys);
436
+ if (keys.has(action.key)) keys.delete(action.key);
437
+ else keys.add(action.key);
438
+ return {
439
+ active: true,
440
+ keys
441
+ };
442
+ }
443
+ function object(value) {
444
+ return typeof value === "object" && value !== null;
445
+ }
446
+ function readNativeChat(value) {
447
+ if (!object(value) || !object(value.nodes) || typeof value.nodes.get !== "function" || typeof value.nodes.source !== "function") return;
448
+ return value;
449
+ }
450
+ function isSelectableNativeNode(value) {
451
+ if (!object(value) || typeof value.key !== "string" || value.target !== "chat" || value.visibility !== "visible") return false;
452
+ if (value.kind === "user") return true;
453
+ if (value.kind !== "assistant-step" || !object(value.data) || value.data.status !== "settled" || !Array.isArray(value.data.blocks)) return false;
454
+ return value.data.blocks.some((block) => object(block) && block.kind === "text" && typeof block.text === "string" && block.text.trim() !== "");
455
+ }
456
+ /** A missing projection may be unloaded; a present ineligible node is authoritative. */
457
+ function observeSelectedNativeNodes(chat, keys, remove, fail) {
458
+ const subscriptions = [];
459
+ const dispose = () => {
460
+ subscriptions.splice(0).forEach((unsubscribe) => unsubscribe());
461
+ };
462
+ try {
463
+ for (const key of keys) {
464
+ const check = () => {
465
+ try {
466
+ const node = chat.nodes.get(key);
467
+ if (node !== void 0 && (!isSelectableNativeNode(node) || node.key !== key)) remove(key);
468
+ } catch {
469
+ fail();
470
+ }
471
+ };
472
+ subscriptions.push(chat.nodes.source(key).subscribe(check));
473
+ check();
474
+ }
475
+ return dispose;
476
+ } catch (error) {
477
+ dispose();
478
+ throw error;
479
+ }
480
+ }
481
+ /** Native user content and assistant display blocks are separate host contracts. */
482
+ function nativeSelectionCopyText(chat, key) {
483
+ const node = chat.nodes.get(key);
484
+ if (!isSelectableNativeNode(node) || node.key !== key || !("data" in node) || !object(node.data)) throw new Error("当前消息暂不可用,请重新选择");
485
+ const blocks = node.kind === "user" ? node.data.content : node.data.blocks;
486
+ if (!Array.isArray(blocks)) throw new Error("当前消息暂不可用,请重新选择");
487
+ return blocks.filter((block) => object(block) && (node.kind === "user" ? block.type : block.kind) === "text" && typeof block.text === "string").map((block) => block.text).join("").trim();
488
+ }
489
+ //#endregion
490
+ //#region src/client/harness-native-selection-geometry.ts
491
+ const ROW = "[data-chat-anchor-key][data-chat-flow-kind]";
492
+ const HIT = 32;
493
+ const GAP = 10;
494
+ const nativeSelectionActionOverlayCss = `
495
+ :has(> [data-slot="conversation.input.dock"] > [data-arkme-native-selection="actions"]) { position: relative; }
496
+ [data-slot="conversation.input.dock"] > [data-arkme-native-selection="actions"] { position: absolute; inset: 0; z-index: 1; }
497
+ [data-slot="conversation.input.dock"]:has(> [data-arkme-native-selection="actions"]) + [data-slot="conversation.composer.bar"] { visibility: hidden; }
498
+ `;
499
+ function nativeSelectionHighlightSelector(keys) {
500
+ return [...keys].map((key) => {
501
+ const escaped = key.replace(/[^\w-]/gu, (character) => `\\${character.codePointAt(0).toString(16)} `);
502
+ return `[data-chat-flow] ${ROW}[data-chat-anchor-key="${escaped}"]`;
503
+ }).join(",");
504
+ }
505
+ function viewportBounds(viewport) {
506
+ const box = viewport.getBoundingClientRect();
507
+ const left = box.left + viewport.clientLeft;
508
+ const top = box.top + viewport.clientTop;
509
+ return {
510
+ left,
511
+ top,
512
+ right: left + viewport.clientWidth,
513
+ bottom: top + viewport.clientHeight
514
+ };
515
+ }
516
+ function measureNativeSelection(viewport, flow, row) {
517
+ const clip = viewportBounds(viewport);
518
+ const column = flow.getBoundingClientRect();
519
+ const box = row.getBoundingClientRect();
520
+ let left = column.left - HIT - GAP;
521
+ if (!row.isConnected || row.hidden || box.width <= 0 || box.height <= 0 || left < Math.max(0, clip.left) || left + HIT > Math.min(row.ownerDocument.defaultView.innerWidth, clip.right) || box.top < Math.max(0, clip.top) || box.top + HIT > Math.min(row.ownerDocument.defaultView.innerHeight, clip.bottom)) return;
522
+ if (typeof row.ownerDocument.elementsFromPoint === "function") {
523
+ const clear = (candidate) => [
524
+ [candidate + 1, box.top + 1],
525
+ [candidate + HIT / 2, box.top + HIT / 2],
526
+ [candidate + HIT - 1, box.top + HIT - 1]
527
+ ].every(([x, y]) => {
528
+ const underlying = row.ownerDocument.elementsFromPoint(x, y).find((element) => !element.closest("[data-arkme-native-selection]"));
529
+ return underlying && viewport.contains(underlying) && (underlying === viewport || underlying.contains(flow) || underlying === flow || row.contains(underlying));
530
+ });
531
+ if (!clear(left)) {
532
+ const edge = Math.max(0, clip.left);
533
+ const outer = [edge + 8, edge].find((candidate) => candidate <= left && clear(candidate));
534
+ if (outer === void 0) return;
535
+ left = outer;
536
+ }
537
+ }
538
+ return {
539
+ left,
540
+ top: box.top
541
+ };
542
+ }
543
+ function sameSelectionPosition(a, b) {
544
+ return b !== void 0 && Math.abs(a.left - b.left) < 1 && Math.abs(a.top - b.top) < 1;
545
+ }
546
+ /** Only the adapter knows native DOM attributes. No styles or attributes are written to host elements. */
547
+ function watchNativeSelectionGeometry(options) {
548
+ const { doc } = options;
549
+ const win = doc.defaultView;
550
+ const flows = doc.querySelectorAll("[data-chat-flow]");
551
+ if (flows.length !== 1) throw new Error("Native chat flow unavailable");
552
+ const flow = flows[0];
553
+ let parent = flow.parentElement;
554
+ while (parent && !["auto", "scroll"].includes(win.getComputedStyle(parent).overflowY)) parent = parent.parentElement;
555
+ if (!parent) throw new Error("Native chat viewport unavailable");
556
+ const viewport = parent;
557
+ const rows = /* @__PURE__ */ new Set();
558
+ const visible = /* @__PURE__ */ new Set();
559
+ const subscriptions = /* @__PURE__ */ new Map();
560
+ let stopped = false;
561
+ let frame = 0;
562
+ let nodeStore = options.chat().nodes;
563
+ const guard = (work) => {
564
+ if (stopped) return;
565
+ try {
566
+ work();
567
+ } catch {
568
+ dispose();
569
+ options.fail();
570
+ }
571
+ };
572
+ const schedule = () => {
573
+ if (stopped) return;
574
+ if (!frame) frame = win.requestAnimationFrame(() => {
575
+ frame = 0;
576
+ guard(publish);
577
+ });
578
+ };
579
+ const resize = new win.ResizeObserver(schedule);
580
+ const intersection = new win.IntersectionObserver((entries) => guard(() => {
581
+ for (const entry of entries) {
582
+ const row = entry.target;
583
+ if (entry.isIntersecting && rows.has(row)) {
584
+ visible.add(row);
585
+ resize.observe(row);
586
+ } else {
587
+ visible.delete(row);
588
+ resize.unobserve(row);
589
+ subscriptions.get(row)?.unsubscribe();
590
+ subscriptions.delete(row);
591
+ }
592
+ }
593
+ schedule();
594
+ }), { root: viewport });
595
+ const remove = (row) => {
596
+ intersection.unobserve(row);
597
+ resize.unobserve(row);
598
+ rows.delete(row);
599
+ visible.delete(row);
600
+ subscriptions.get(row)?.unsubscribe();
601
+ subscriptions.delete(row);
602
+ };
603
+ const addTree = (node) => {
604
+ if (!(node instanceof win.HTMLElement)) return;
605
+ const candidates = node.matches(ROW) ? [node] : [...node.querySelectorAll(ROW)];
606
+ for (const row of candidates) {
607
+ if (row.closest("[data-chat-flow]") !== flow || row.parentElement?.closest(ROW) || rows.has(row)) continue;
608
+ rows.add(row);
609
+ intersection.observe(row);
610
+ }
611
+ };
612
+ const mutation = new win.MutationObserver((records) => guard(() => {
613
+ for (const record of records) {
614
+ for (const node of record.addedNodes) addTree(node);
615
+ for (const node of record.removedNodes) {
616
+ if (!(node instanceof win.HTMLElement)) continue;
617
+ const removed = node.matches(ROW) ? [node, ...node.querySelectorAll(ROW)] : [...node.querySelectorAll(ROW)];
618
+ for (const row of removed) if (!flow.contains(row)) remove(row);
619
+ }
620
+ if (record.type === "attributes" && record.target instanceof win.HTMLElement && record.target.matches(ROW)) addTree(record.target);
621
+ }
622
+ schedule();
623
+ }));
624
+ function publish() {
625
+ if (!flow.isConnected || !viewport.isConnected) throw new Error("Native chat flow replaced");
626
+ const chat = options.chat();
627
+ if (nodeStore !== chat.nodes) {
628
+ subscriptions.forEach((value) => value.unsubscribe());
629
+ subscriptions.clear();
630
+ nodeStore = chat.nodes;
631
+ }
632
+ const seats = [];
633
+ const seen = /* @__PURE__ */ new Set();
634
+ let blocked = false;
635
+ for (const row of visible) {
636
+ const key = row.dataset.chatAnchorKey;
637
+ if (!key) continue;
638
+ if (subscriptions.get(row)?.key !== key) {
639
+ subscriptions.get(row)?.unsubscribe();
640
+ subscriptions.set(row, {
641
+ key,
642
+ unsubscribe: chat.nodes.source(key).subscribe(schedule)
643
+ });
644
+ }
645
+ const node = chat.nodes.get(key);
646
+ if (!isSelectableNativeNode(node) || node.key !== key || node.kind !== row.dataset.chatFlowKind) continue;
647
+ if (seen.has(key)) throw new Error("Ambiguous native message anchor");
648
+ seen.add(key);
649
+ const position = measureNativeSelection(viewport, flow, row);
650
+ if (position) seats.push({
651
+ key,
652
+ row,
653
+ ...position
654
+ });
655
+ else {
656
+ const box = row.getBoundingClientRect();
657
+ const clip = viewportBounds(viewport);
658
+ if (box.width > 0 && box.height > 0 && box.top >= Math.max(0, clip.top) && box.top + HIT <= Math.min(win.innerHeight, clip.bottom)) blocked = true;
659
+ }
660
+ }
661
+ seats.sort((a, b) => a.top - b.top);
662
+ const cramped = flow.getBoundingClientRect().left - viewportBounds(viewport).left < 42;
663
+ const column = flow.getBoundingClientRect();
664
+ const bounds = viewportBounds(viewport);
665
+ const docks = doc.querySelectorAll("[data-slot=\"conversation.input.dock\"]");
666
+ options.publish({
667
+ seats,
668
+ cramped: cramped || blocked && seats.length === 0,
669
+ viewport,
670
+ highlight: {
671
+ left: Math.max(0, column.left - bounds.left - 8),
672
+ right: Math.max(0, bounds.right - column.right - 8)
673
+ },
674
+ ...docks.length === 1 && docks[0].nextElementSibling?.matches("[data-slot=\"conversation.composer.bar\"]") ? { actionDock: docks[0] } : {}
675
+ });
676
+ }
677
+ function dispose() {
678
+ if (stopped) return;
679
+ stopped = true;
680
+ if (frame) win.cancelAnimationFrame(frame);
681
+ mutation.disconnect();
682
+ intersection.disconnect();
683
+ resize.disconnect();
684
+ subscriptions.forEach((value) => value.unsubscribe());
685
+ subscriptions.clear();
686
+ viewport.removeEventListener("scroll", schedule);
687
+ win.removeEventListener("resize", schedule);
688
+ win.removeEventListener("scroll", schedule, true);
689
+ win.visualViewport?.removeEventListener("resize", schedule);
690
+ win.visualViewport?.removeEventListener("scroll", schedule);
691
+ }
692
+ try {
693
+ addTree(flow);
694
+ mutation.observe(flow, {
695
+ childList: true,
696
+ subtree: true,
697
+ attributes: true,
698
+ attributeFilter: [
699
+ "data-chat-anchor-key",
700
+ "data-chat-flow-kind",
701
+ "hidden",
702
+ "class",
703
+ "style"
704
+ ]
705
+ });
706
+ resize.observe(flow);
707
+ resize.observe(viewport);
708
+ viewport.addEventListener("scroll", schedule, { passive: true });
709
+ win.addEventListener("resize", schedule);
710
+ win.addEventListener("scroll", schedule, {
711
+ passive: true,
712
+ capture: true
713
+ });
714
+ win.visualViewport?.addEventListener("resize", schedule);
715
+ win.visualViewport?.addEventListener("scroll", schedule);
716
+ schedule();
717
+ } catch (error) {
718
+ dispose();
719
+ throw error;
720
+ }
721
+ return {
722
+ dispose,
723
+ refresh: schedule,
724
+ valid(seat) {
725
+ if (stopped || frame || !flow.isConnected || !flow.contains(seat.row)) return false;
726
+ const node = options.chat().nodes.get(seat.key);
727
+ return isSelectableNativeNode(node) && node.key === seat.key && node.kind === seat.row.dataset.chatFlowKind && seat.row.dataset.chatAnchorKey === seat.key && sameSelectionPosition(seat, measureNativeSelection(viewport, flow, seat.row));
728
+ }
729
+ };
730
+ }
731
+ /** Header slots do not inherit the native header's private view/store hooks. */
732
+ function observeNativeChatPresence(doc, publish) {
733
+ let flow = doc.querySelector("[data-chat-flow]");
734
+ publish(flow !== null);
735
+ const observer = new doc.defaultView.MutationObserver((records) => {
736
+ if (flow?.isConnected || !records.some((record) => record.addedNodes.length || record.removedNodes.length)) return;
737
+ const next = doc.querySelector("[data-chat-flow]");
738
+ if (next !== flow) {
739
+ flow = next;
740
+ publish(next !== null);
741
+ }
742
+ });
743
+ observer.observe(doc.body, {
744
+ childList: true,
745
+ subtree: true
746
+ });
747
+ return () => observer.disconnect();
748
+ }
749
+ /** Resolve a selectable message body for pointer actions; native controls keep their own behavior. */
750
+ function nativeSelectionMessageRow(doc, target, chat) {
751
+ if (!(target instanceof doc.defaultView.Element) || target.closest("button, a, input, textarea, select, [role=\"link\"], [role=\"button\"], [contenteditable]:not([contenteditable=\"false\"]), [role=\"menu\"], [role=\"dialog\"]")) return;
752
+ const row = target.closest(ROW);
753
+ const flows = doc.querySelectorAll("[data-chat-flow]");
754
+ if (!row?.isConnected || row.hidden || flows.length !== 1 || row.closest("[data-chat-flow]") !== flows[0]) return;
755
+ const key = row.dataset.chatAnchorKey;
756
+ if (!key || [...flows[0].querySelectorAll(ROW)].filter((candidate) => candidate.dataset.chatAnchorKey === key).length !== 1) return;
757
+ const node = chat.nodes.get(key);
758
+ return isSelectableNativeNode(node) && node.key === key && node.kind === row.dataset.chatFlowKind ? {
759
+ key,
760
+ row
761
+ } : void 0;
762
+ }
763
+ /** Expanded row paint is outside the native row box; resolve only bare scroll/flow space. */
764
+ function nativeSelectionPointerRow(doc, event, chat, viewport) {
765
+ const direct = nativeSelectionMessageRow(doc, event.target, chat);
766
+ if (direct) return direct;
767
+ const target = event.target;
768
+ if (!viewport?.isConnected || !(target instanceof doc.defaultView.Element) || !viewport.contains(target)) return;
769
+ const flow = viewport.querySelector("[data-chat-flow]");
770
+ if (!flow || !(target === viewport || target === flow || target.contains(flow))) return;
771
+ const clip = viewportBounds(viewport);
772
+ if (event.clientX < clip.left + 8 || event.clientX > clip.right - 8 || event.clientY < clip.top || event.clientY > clip.bottom) return;
773
+ let nearest;
774
+ let distance = Infinity;
775
+ let ambiguous = false;
776
+ for (const row of flow.querySelectorAll(ROW)) {
777
+ if (row.hidden || row.parentElement?.closest(ROW)) continue;
778
+ const box = row.getBoundingClientRect();
779
+ if (box.width <= 0 || box.height <= 0 || event.clientY < box.top - 8 || event.clientY > box.bottom + 8) continue;
780
+ const gap = Math.max(box.top - event.clientY, event.clientY - box.bottom, 0);
781
+ if (gap < distance) {
782
+ nearest = row;
783
+ distance = gap;
784
+ ambiguous = false;
785
+ } else if (gap === distance) ambiguous = true;
786
+ }
787
+ return nearest && !ambiguous ? nativeSelectionMessageRow(doc, nearest, chat) : void 0;
788
+ }
789
+ //#endregion
790
+ //#region src/client/harness-native-selection-client.tsx
791
+ const SLOT = "conversation.session.header.actions";
792
+ const buttonStyle = {
793
+ display: "inline-flex",
794
+ alignItems: "center",
795
+ gap: 5,
796
+ border: 0,
797
+ borderRadius: 6,
798
+ padding: "5px 8px",
799
+ background: "transparent",
800
+ color: arkmeTheme.text,
801
+ cursor: "pointer",
802
+ font: "inherit"
803
+ };
804
+ const EMPTY_LAYOUT = {
805
+ seats: [],
806
+ cramped: false,
807
+ viewport: null
808
+ };
809
+ var SelectionBoundary = class extends react.Component {
810
+ state = { failed: false };
811
+ static getDerivedStateFromError() {
812
+ return { failed: true };
813
+ }
814
+ componentDidCatch() {
815
+ console.warn("Arkme native selection disabled after a rendering error.");
816
+ }
817
+ render() {
818
+ return this.state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
819
+ role: "status",
820
+ children: "多选暂不可用"
821
+ }) : this.props.children;
822
+ }
823
+ };
824
+ function NativeSelectionHeader({ sessionId, useChat, doc = document }) {
825
+ if (typeof useChat !== "function") return null;
826
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeSelectionView, {
827
+ useChat,
828
+ doc
829
+ }) }, sessionId);
830
+ }
831
+ function NativeSelectionView({ useChat, doc }) {
832
+ const [present, setPresent] = (0, react.useState)(false);
833
+ (0, react.useLayoutEffect)(() => observeNativeChatPresence(doc, setPresent), [doc]);
834
+ return present ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeSelectionSession, {
835
+ useChat,
836
+ doc
837
+ }) : null;
838
+ }
839
+ function NativeCopyTextAction({ chat, selectedKey, doc }) {
840
+ const [status, setStatus] = (0, react.useState)("");
841
+ const [busy, setBusy] = (0, react.useState)(false);
842
+ const pending = (0, react.useRef)(false);
843
+ const alive = (0, react.useRef)(true);
844
+ (0, react.useEffect)(() => {
845
+ alive.current = true;
846
+ return () => {
847
+ alive.current = false;
848
+ };
849
+ }, []);
850
+ (0, react.useEffect)(() => {
851
+ if (!status) return;
852
+ const timer = doc.defaultView.setTimeout(() => setStatus(""), 2800);
853
+ return () => doc.defaultView.clearTimeout(timer);
854
+ }, [status, doc]);
855
+ const copy = async () => {
856
+ if (!selectedKey || pending.current) return;
857
+ pending.current = true;
858
+ setBusy(true);
859
+ try {
860
+ const value = nativeSelectionCopyText(chat, selectedKey);
861
+ if (!value) {
862
+ setStatus("当前消息没有可复制文本");
863
+ return;
864
+ }
865
+ await copyText(value, doc);
866
+ if (alive.current) setStatus("已复制");
867
+ } catch (error) {
868
+ if (alive.current) setStatus(error instanceof Error ? error.message : "复制失败,请稍后重试");
869
+ } finally {
870
+ pending.current = false;
871
+ if (alive.current) setBusy(false);
872
+ }
873
+ };
874
+ const disabled = selectedKey === void 0 || busy;
875
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
876
+ type: "button",
877
+ "aria-label": "复制文本",
878
+ disabled,
879
+ onClick: () => {
880
+ copy();
881
+ },
882
+ style: {
883
+ ...messageSelectionStyles.selectBarButton,
884
+ ...disabled ? messageSelectionStyles.selectBarButtonDisabled : {}
885
+ },
886
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
887
+ style: messageSelectionStyles.selectBarIconTile,
888
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeSelectActionIcon, {
889
+ kind: "copy",
890
+ size: 22
891
+ })
892
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
893
+ style: messageSelectionStyles.selectBarLabel,
894
+ children: busy ? "复制中…" : "复制文本"
895
+ })]
896
+ }), status && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
897
+ role: "status",
898
+ style: {
899
+ position: "absolute",
900
+ top: 4,
901
+ left: 0,
902
+ right: 0,
903
+ textAlign: "center",
904
+ fontSize: 12,
905
+ color: arkmeTheme.secondary
906
+ },
907
+ children: status
908
+ })] });
909
+ }
910
+ function NativeSelectionSession({ useChat, doc }) {
911
+ const snapshot = useChat((value) => value);
912
+ const chat = readNativeChat(snapshot);
913
+ const chatRef = (0, react.useRef)(chat);
914
+ chatRef.current = chat;
915
+ const [state, dispatch] = (0, react.useReducer)(nativeSelectionReducer, EMPTY_NATIVE_SELECTION);
916
+ const [layout, setLayout] = (0, react.useState)(EMPTY_LAYOUT);
917
+ const [failed, setFailed] = (0, react.useState)(false);
918
+ const [visible, setVisible] = (0, react.useState)(false);
919
+ const layer = (0, react.useRef)(null);
920
+ const entry = (0, react.useRef)(null);
921
+ const [menu, setMenu] = (0, react.useState)(null);
922
+ const restoreFocus = (0, react.useRef)(false);
923
+ const watcher = (0, react.useRef)(void 0);
924
+ const fail = () => {
925
+ setMenu(null);
926
+ dispatch({ type: "exit" });
927
+ setLayout(EMPTY_LAYOUT);
928
+ setFailed(true);
929
+ };
930
+ (0, react.useLayoutEffect)(() => {
931
+ const surface = doc.defaultView?.frameElement?.parentElement;
932
+ if (surface?.getAttribute("data-arkme-owned") !== "deepseek-harness-surface") return;
933
+ let account = surface.getAttribute("data-arkme-account-scope");
934
+ let accountId = surface.getAttribute("data-arkme-account-id");
935
+ const sync = () => {
936
+ const next = surface.getAttribute("data-arkme-visible") === "true";
937
+ const nextAccount = surface.getAttribute("data-arkme-account-scope");
938
+ const nextAccountId = surface.getAttribute("data-arkme-account-id");
939
+ if (!next || nextAccount !== account || nextAccountId !== accountId) {
940
+ setMenu(null);
941
+ dispatch({ type: "exit" });
942
+ }
943
+ account = nextAccount;
944
+ accountId = nextAccountId;
945
+ setVisible(next);
946
+ };
947
+ const observer = new MutationObserver(sync);
948
+ observer.observe(surface, {
949
+ attributes: true,
950
+ attributeFilter: [
951
+ "data-arkme-visible",
952
+ "data-arkme-account-scope",
953
+ "data-arkme-account-id"
954
+ ]
955
+ });
956
+ const exit = () => {
957
+ setMenu(null);
958
+ dispatch({ type: "exit" });
959
+ };
960
+ doc.defaultView.addEventListener("pagehide", exit);
961
+ sync();
962
+ return () => {
963
+ observer.disconnect();
964
+ doc.defaultView.removeEventListener("pagehide", exit);
965
+ };
966
+ }, [doc]);
967
+ (0, react.useLayoutEffect)(() => {
968
+ if (!state.active || !visible || failed) return;
969
+ if (!chatRef.current) {
970
+ fail();
971
+ return;
972
+ }
973
+ try {
974
+ watcher.current = watchNativeSelectionGeometry({
975
+ doc,
976
+ chat: () => {
977
+ if (!chatRef.current) throw new Error("Native chat contract changed");
978
+ return chatRef.current;
979
+ },
980
+ publish: setLayout,
981
+ fail
982
+ });
983
+ } catch {
984
+ fail();
985
+ }
986
+ return () => {
987
+ watcher.current?.dispose();
988
+ watcher.current = void 0;
989
+ setLayout(EMPTY_LAYOUT);
990
+ };
991
+ }, [
992
+ state.active,
993
+ visible,
994
+ failed,
995
+ doc
996
+ ]);
997
+ (0, react.useLayoutEffect)(() => {
998
+ if (!layer.current) return;
999
+ const origin = layer.current.getBoundingClientRect();
1000
+ layer.current.style.setProperty("--arkme-selection-origin-x", `${origin.left}px`);
1001
+ layer.current.style.setProperty("--arkme-selection-origin-y", `${origin.top}px`);
1002
+ layer.current.style.visibility = "visible";
1003
+ }, [layout]);
1004
+ (0, react.useLayoutEffect)(() => {
1005
+ if (!state.active && restoreFocus.current) {
1006
+ entry.current?.focus();
1007
+ restoreFocus.current = false;
1008
+ }
1009
+ }, [state.active]);
1010
+ (0, react.useEffect)(() => {
1011
+ watcher.current?.refresh();
1012
+ }, [snapshot]);
1013
+ (0, react.useEffect)(() => {
1014
+ if (!chat || !state.active) return;
1015
+ try {
1016
+ return observeSelectedNativeNodes(chat, state.keys, (key) => dispatch({
1017
+ type: "remove",
1018
+ key
1019
+ }), fail);
1020
+ } catch {
1021
+ fail();
1022
+ }
1023
+ }, [
1024
+ chat?.nodes,
1025
+ state.active,
1026
+ state.keys
1027
+ ]);
1028
+ (0, react.useEffect)(() => {
1029
+ if (!visible || failed || !chat) return;
1030
+ const open = (event) => {
1031
+ if (event.defaultPrevented || state.active) return;
1032
+ try {
1033
+ const target = nativeSelectionMessageRow(doc, event.target, chat);
1034
+ if (!target) return;
1035
+ event.preventDefault();
1036
+ event.stopPropagation();
1037
+ entry.current = doc.activeElement instanceof doc.defaultView.HTMLElement ? doc.activeElement : null;
1038
+ setMenu({
1039
+ ...target,
1040
+ autoFocus: event.button !== 2,
1041
+ x: Math.max(8, Math.min(event.clientX, doc.defaultView.innerWidth - 186)),
1042
+ y: Math.max(8, Math.min(event.clientY, doc.defaultView.innerHeight - 56))
1043
+ });
1044
+ } catch {
1045
+ fail();
1046
+ }
1047
+ };
1048
+ doc.addEventListener("contextmenu", open);
1049
+ return () => doc.removeEventListener("contextmenu", open);
1050
+ }, [
1051
+ visible,
1052
+ failed,
1053
+ chat,
1054
+ state.active,
1055
+ doc
1056
+ ]);
1057
+ (0, react.useEffect)(() => {
1058
+ if (!state.active || !visible || failed || !chat) return;
1059
+ const resolve = (event) => nativeSelectionPointerRow(doc, event, chat, layout.viewport);
1060
+ const preventTextSelection = (event) => {
1061
+ if (event.defaultPrevented || event.button !== 0) return;
1062
+ try {
1063
+ if (resolve(event)) event.preventDefault();
1064
+ } catch {
1065
+ fail();
1066
+ }
1067
+ };
1068
+ const toggle = (event) => {
1069
+ if (event.defaultPrevented || event.button !== 0) return;
1070
+ try {
1071
+ const target = resolve(event);
1072
+ if (target) dispatch({
1073
+ type: "toggle",
1074
+ key: target.key
1075
+ });
1076
+ } catch {
1077
+ fail();
1078
+ }
1079
+ };
1080
+ doc.addEventListener("mousedown", preventTextSelection);
1081
+ doc.addEventListener("click", toggle);
1082
+ return () => {
1083
+ doc.removeEventListener("mousedown", preventTextSelection);
1084
+ doc.removeEventListener("click", toggle);
1085
+ };
1086
+ }, [
1087
+ state.active,
1088
+ visible,
1089
+ failed,
1090
+ chat,
1091
+ doc,
1092
+ layout.viewport
1093
+ ]);
1094
+ (0, react.useEffect)(() => {
1095
+ if (!menu) return;
1096
+ const close = () => setMenu(null);
1097
+ const outside = (event) => {
1098
+ if (!(event.target instanceof doc.defaultView.Element) || !event.target.closest("[data-arkme-native-selection=\"menu\"]")) close();
1099
+ };
1100
+ const keydown = (event) => {
1101
+ if (event.key === "Escape") {
1102
+ event.preventDefault();
1103
+ event.stopPropagation();
1104
+ close();
1105
+ entry.current?.focus();
1106
+ }
1107
+ };
1108
+ doc.addEventListener("mousedown", outside);
1109
+ doc.addEventListener("keydown", keydown, true);
1110
+ doc.defaultView.addEventListener("resize", close);
1111
+ doc.addEventListener("scroll", close, true);
1112
+ return () => {
1113
+ doc.removeEventListener("mousedown", outside);
1114
+ doc.removeEventListener("keydown", keydown, true);
1115
+ doc.defaultView.removeEventListener("resize", close);
1116
+ doc.removeEventListener("scroll", close, true);
1117
+ };
1118
+ }, [menu, doc]);
1119
+ if (!visible) return null;
1120
+ if (failed || !chat) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1121
+ role: "status",
1122
+ children: "多选暂不可用"
1123
+ });
1124
+ const exit = () => {
1125
+ restoreFocus.current = true;
1126
+ dispatch({ type: "exit" });
1127
+ };
1128
+ const escape = (event) => {
1129
+ if (event.key !== "Escape" || doc.querySelector("[role=\"dialog\"][aria-modal=\"true\"], dialog[open], [role=\"menu\"]")) return;
1130
+ event.stopPropagation();
1131
+ exit();
1132
+ };
1133
+ const highlightSelector = nativeSelectionHighlightSelector(state.keys);
1134
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1135
+ state.active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", {
1136
+ "data-arkme-native-selection": "highlight",
1137
+ children: state.keys.size > 0 ? `${highlightSelector} { position: relative; isolation: isolate; }
1138
+ ${highlightSelector.split(",").map((selector) => `${selector}::before`).join(",")} {
1139
+ content: ""; position: absolute; pointer-events: none; z-index: -1;
1140
+ top: -8px; bottom: -8px; left: -${layout.highlight?.left ?? 0}px; right: -${layout.highlight?.right ?? 0}px;
1141
+ border-radius: 6px; background: ${messageSelectionStyles.rowSelectedForAction.background};
1142
+ }` : ""
1143
+ }),
1144
+ state.active && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1145
+ "data-arkme-native-selection": "header",
1146
+ onKeyDown: escape,
1147
+ style: {
1148
+ display: "flex",
1149
+ alignItems: "center",
1150
+ gap: 6,
1151
+ color: arkmeTheme.text,
1152
+ fontSize: 12
1153
+ },
1154
+ children: [
1155
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1156
+ role: "status",
1157
+ "aria-live": "polite",
1158
+ children: [
1159
+ "已选 ",
1160
+ state.keys.size,
1161
+ " 条"
1162
+ ]
1163
+ }),
1164
+ layout.cramped && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1165
+ role: "status",
1166
+ style: { color: arkmeTheme.secondary },
1167
+ children: "请扩大窗口以勾选消息"
1168
+ }),
1169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1170
+ type: "button",
1171
+ style: buttonStyle,
1172
+ onClick: exit,
1173
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeSelectActionIcon, {
1174
+ kind: "close",
1175
+ size: 16
1176
+ }), "退出"]
1177
+ })
1178
+ ]
1179
+ }),
1180
+ menu && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1181
+ "data-arkme-native-selection": "menu",
1182
+ role: "menu",
1183
+ "aria-label": "消息操作",
1184
+ style: {
1185
+ ...messageSelectionMenuStyles.menu,
1186
+ left: menu.x,
1187
+ top: menu.y
1188
+ },
1189
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1190
+ autoFocus: menu.autoFocus,
1191
+ type: "button",
1192
+ role: "menuitem",
1193
+ style: messageSelectionMenuStyles.menuButton,
1194
+ onClick: () => {
1195
+ setMenu(null);
1196
+ try {
1197
+ if (nativeSelectionMessageRow(doc, menu.row, chat)?.key === menu.key) dispatch({
1198
+ type: "enter",
1199
+ key: menu.key
1200
+ });
1201
+ } catch {
1202
+ fail();
1203
+ }
1204
+ },
1205
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1206
+ style: messageSelectionMenuStyles.menuIcon,
1207
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeSelectActionIcon, {
1208
+ kind: "select",
1209
+ size: 16
1210
+ })
1211
+ }), "多选"]
1212
+ })
1213
+ }), doc.body),
1214
+ state.active && layout.actionDock && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1215
+ "data-arkme-native-selection": "actions",
1216
+ role: "group",
1217
+ "aria-label": "多选操作",
1218
+ onKeyDown: escape,
1219
+ style: {
1220
+ ...messageSelectionStyles.selectBar,
1221
+ height: "100%",
1222
+ borderTop: 0
1223
+ },
1224
+ children: [
1225
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: nativeSelectionActionOverlayCss }),
1226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeCopyTextAction, {
1227
+ chat,
1228
+ selectedKey: state.keys.size === 1 ? [...state.keys][0] : void 0,
1229
+ doc
1230
+ }, state.keys.size === 1 ? [...state.keys][0] : "no-single-selection"),
1231
+ [{
1232
+ kind: "link",
1233
+ label: "复制链接"
1234
+ }, {
1235
+ kind: "forward",
1236
+ label: "转发"
1237
+ }].map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1238
+ type: "button",
1239
+ disabled: true,
1240
+ title: "暂未接入",
1241
+ "aria-label": action.label,
1242
+ style: {
1243
+ ...messageSelectionStyles.selectBarButton,
1244
+ ...messageSelectionStyles.selectBarButtonDisabled
1245
+ },
1246
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1247
+ style: messageSelectionStyles.selectBarIconTile,
1248
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeSelectActionIcon, {
1249
+ kind: action.kind,
1250
+ size: 22
1251
+ })
1252
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1253
+ style: messageSelectionStyles.selectBarLabel,
1254
+ children: action.label
1255
+ })]
1256
+ }, action.kind)),
1257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1258
+ type: "button",
1259
+ "aria-label": "退出多选",
1260
+ style: messageSelectionStyles.selectBarButton,
1261
+ onClick: exit,
1262
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1263
+ style: messageSelectionStyles.selectBarIconTile,
1264
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeSelectActionIcon, {
1265
+ kind: "close",
1266
+ size: 18
1267
+ })
1268
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1269
+ style: messageSelectionStyles.selectBarLabel,
1270
+ children: "退出多选"
1271
+ })]
1272
+ })
1273
+ ]
1274
+ }), layout.actionDock),
1275
+ state.active && layout.viewport && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1276
+ ref: layer,
1277
+ "data-arkme-native-selection": "controls",
1278
+ onKeyDown: escape,
1279
+ style: {
1280
+ position: "relative",
1281
+ width: 0,
1282
+ height: 0,
1283
+ overflowAnchor: "none",
1284
+ pointerEvents: "none",
1285
+ zIndex: 20
1286
+ },
1287
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: "[data-arkme-native-selection] button:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #8295e8); outline-offset: 2px; }" }), !layout.cramped && layout.seats.map((seat) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1288
+ "data-arkme-native-selection-key": seat.key,
1289
+ style: {
1290
+ position: "absolute",
1291
+ left: `calc(${seat.left}px - var(--arkme-selection-origin-x, 0px))`,
1292
+ top: `calc(${seat.top}px - var(--arkme-selection-origin-y, 0px))`,
1293
+ pointerEvents: "auto"
1294
+ },
1295
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeMessageSelectionControl, {
1296
+ anchor: "card-center",
1297
+ checked: state.keys.has(seat.key),
1298
+ disabled: false,
1299
+ onToggle: () => {
1300
+ try {
1301
+ if (watcher.current?.valid(seat)) dispatch({
1302
+ type: "toggle",
1303
+ key: seat.key
1304
+ });
1305
+ else watcher.current?.refresh();
1306
+ } catch {
1307
+ fail();
1308
+ }
1309
+ }
1310
+ })
1311
+ }, seat.key))]
1312
+ }), layout.viewport)
1313
+ ] });
1314
+ }
1315
+ /** Register through a public additive slot; never replace native message renderers. */
1316
+ function install(ctx, doc = document) {
1317
+ if (typeof ctx.slots?.spec !== "function") return () => {};
1318
+ return ctx.slots.inject(SLOT, () => {
1319
+ try {
1320
+ const spec = ctx.slots.spec(SLOT);
1321
+ if (spec?.kind !== "list" || spec.scope !== "session") return () => {};
1322
+ return ctx.slots.register({
1323
+ name: SLOT,
1324
+ id: "arkme-native-selection",
1325
+ order: 10
1326
+ }, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeSelectionHeader, {
1327
+ ...props,
1328
+ doc
1329
+ }));
1330
+ } catch {
1331
+ console.warn("Arkme native selection slot unavailable.");
1332
+ return () => {};
1333
+ }
1334
+ });
1335
+ }
1336
+ //#endregion
1337
+ exports.NativeSelectionHeader = NativeSelectionHeader;
1338
+ exports.install = install;
1339
+ return module.exports;
1340
+ }
1341
+ });