@h-ai/ui 0.1.0-alpha.10 → 0.1.0-alpha.11
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.
- package/dist/components/compounds/Modal.svelte +1 -1
- package/dist/components/scenes/ai/AiDocumentEditor.svelte +1410 -272
- package/dist/components/scenes/ai/document-parse.js +4 -2
- package/dist/components/scenes/ai/document-types.d.ts +38 -4
- package/dist/components/scenes/ai/editor-markdown-extensions.d.ts +11 -0
- package/dist/components/scenes/ai/editor-markdown-extensions.js +184 -0
- package/dist/components/scenes/ai/index.d.ts +1 -1
- package/dist/components/scenes/ai/markdown-parse.js +2 -0
- package/dist/messages/en-US.json +19 -0
- package/dist/messages/zh-CN.json +19 -0
- package/package.json +2 -2
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
import type {
|
|
15
15
|
AiDocumentEditorProps,
|
|
16
16
|
MarkdownBlockFormatKind,
|
|
17
|
+
MarkdownBlockStyleKind,
|
|
17
18
|
MarkdownCodeBlockItem,
|
|
18
19
|
MarkdownCodeRunRequest,
|
|
19
20
|
MarkdownCodeRunResult,
|
|
21
|
+
MarkdownColorFormatRequest,
|
|
20
22
|
MarkdownInlineFormatKind,
|
|
21
23
|
MarkdownRewriteAction,
|
|
24
|
+
MarkdownTextAlignKind,
|
|
22
25
|
} from './document-types.js'
|
|
23
26
|
import { uiM } from '../../../messages.js'
|
|
24
27
|
import { cn } from '../../../utils.js'
|
|
@@ -47,6 +50,129 @@
|
|
|
47
50
|
error?: string
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
interface SelectionFormatState {
|
|
54
|
+
/** 当前选区所在段落样式,用于标题/正文下拉默认值。 */
|
|
55
|
+
blockFormat: MarkdownBlockStyleKind
|
|
56
|
+
/** 当前选区所在段落的对齐方式。 */
|
|
57
|
+
alignment: MarkdownTextAlignKind
|
|
58
|
+
/** 当前选区是否命中加粗样式。 */
|
|
59
|
+
bold: boolean
|
|
60
|
+
/** 当前选区是否命中删除线样式。 */
|
|
61
|
+
strike: boolean
|
|
62
|
+
/** 当前选区是否命中斜体样式。 */
|
|
63
|
+
italic: boolean
|
|
64
|
+
/** 当前选区是否命中下划线样式。 */
|
|
65
|
+
underline: boolean
|
|
66
|
+
/** 当前选区是否命中 `<mark>` 或自定义底色高亮。 */
|
|
67
|
+
highlight: boolean
|
|
68
|
+
/** 当前选区是否落在行内代码内。 */
|
|
69
|
+
code: boolean
|
|
70
|
+
/** 当前选区命中的链接地址;为空表示无链接。 */
|
|
71
|
+
linkHref: string
|
|
72
|
+
/** 当前选区前景色;为空表示使用默认文字颜色。 */
|
|
73
|
+
textColor: string | null
|
|
74
|
+
/** 当前选区背景色;为空表示使用默认背景。 */
|
|
75
|
+
backgroundColor: string | null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface PreviewSelectionState {
|
|
79
|
+
/** 浏览器当前仍然有效的正文选区。 */
|
|
80
|
+
selection: Selection
|
|
81
|
+
/** 当前选区对应的 DOM Range,用于计算浮层定位。 */
|
|
82
|
+
range: Range
|
|
83
|
+
/** 归一化后的选中文本。 */
|
|
84
|
+
text: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type SelectionMenuKind = 'rewrite' | 'block' | 'align' | 'link' | 'color'
|
|
88
|
+
|
|
89
|
+
const BLOCK_FORMAT_OPTIONS: Array<{
|
|
90
|
+
value: MarkdownBlockStyleKind
|
|
91
|
+
labelKey:
|
|
92
|
+
| 'markdown_format_paragraph'
|
|
93
|
+
| 'markdown_format_heading_1'
|
|
94
|
+
| 'markdown_format_heading_2'
|
|
95
|
+
| 'markdown_format_heading_3'
|
|
96
|
+
| 'markdown_format_heading_4'
|
|
97
|
+
shortLabel: string
|
|
98
|
+
}> = [
|
|
99
|
+
{
|
|
100
|
+
value: 'paragraph',
|
|
101
|
+
labelKey: 'markdown_format_paragraph',
|
|
102
|
+
shortLabel: 'T',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: 'heading1',
|
|
106
|
+
labelKey: 'markdown_format_heading_1',
|
|
107
|
+
shortLabel: 'H1',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
value: 'heading2',
|
|
111
|
+
labelKey: 'markdown_format_heading_2',
|
|
112
|
+
shortLabel: 'H2',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
value: 'heading3',
|
|
116
|
+
labelKey: 'markdown_format_heading_3',
|
|
117
|
+
shortLabel: 'H3',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
value: 'heading4',
|
|
121
|
+
labelKey: 'markdown_format_heading_4',
|
|
122
|
+
shortLabel: 'H4',
|
|
123
|
+
},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
const ALIGN_OPTIONS: Array<{
|
|
127
|
+
value: MarkdownTextAlignKind
|
|
128
|
+
labelKey:
|
|
129
|
+
| 'markdown_align_left'
|
|
130
|
+
| 'markdown_align_center'
|
|
131
|
+
| 'markdown_align_right'
|
|
132
|
+
| 'markdown_align_justify'
|
|
133
|
+
}> = [
|
|
134
|
+
{ value: 'left', labelKey: 'markdown_align_left' },
|
|
135
|
+
{ value: 'center', labelKey: 'markdown_align_center' },
|
|
136
|
+
{ value: 'right', labelKey: 'markdown_align_right' },
|
|
137
|
+
{ value: 'justify', labelKey: 'markdown_align_justify' },
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
const TEXT_COLOR_PRESETS = [
|
|
141
|
+
'#0f172a',
|
|
142
|
+
'#475569',
|
|
143
|
+
'#b91c1c',
|
|
144
|
+
'#ea580c',
|
|
145
|
+
'#ca8a04',
|
|
146
|
+
'#15803d',
|
|
147
|
+
'#2563eb',
|
|
148
|
+
'#7c3aed',
|
|
149
|
+
] as const
|
|
150
|
+
|
|
151
|
+
const BACKGROUND_COLOR_PRESETS = [
|
|
152
|
+
'#fee2e2',
|
|
153
|
+
'#ffedd5',
|
|
154
|
+
'#fef3c7',
|
|
155
|
+
'#dcfce7',
|
|
156
|
+
'#dbeafe',
|
|
157
|
+
'#ede9fe',
|
|
158
|
+
'#f3f4f6',
|
|
159
|
+
'#e2e8f0',
|
|
160
|
+
] as const
|
|
161
|
+
|
|
162
|
+
const DEFAULT_SELECTION_FORMAT_STATE: SelectionFormatState = {
|
|
163
|
+
blockFormat: 'paragraph',
|
|
164
|
+
alignment: 'left',
|
|
165
|
+
bold: false,
|
|
166
|
+
strike: false,
|
|
167
|
+
italic: false,
|
|
168
|
+
underline: false,
|
|
169
|
+
highlight: false,
|
|
170
|
+
code: false,
|
|
171
|
+
linkHref: '',
|
|
172
|
+
textColor: null,
|
|
173
|
+
backgroundColor: null,
|
|
174
|
+
}
|
|
175
|
+
|
|
50
176
|
// 复制前后的图标以内联 SVG 缓存,避免每次点击都重新拼接按钮内容。
|
|
51
177
|
const COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`
|
|
52
178
|
const CHECK_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`
|
|
@@ -123,8 +249,16 @@
|
|
|
123
249
|
oncopydocument,
|
|
124
250
|
// 块级格式动作回调。
|
|
125
251
|
onapplyblockformat,
|
|
252
|
+
// 细粒度块样式动作回调。
|
|
253
|
+
onapplyblockstyle,
|
|
126
254
|
// 行内格式动作回调。
|
|
127
255
|
onapplyinlineformat,
|
|
256
|
+
// 对齐动作回调。
|
|
257
|
+
onapplyalignment,
|
|
258
|
+
// 链接设置动作回调。
|
|
259
|
+
onapplylink,
|
|
260
|
+
// 颜色设置动作回调。
|
|
261
|
+
onapplycolor,
|
|
128
262
|
// 选区复制回调。
|
|
129
263
|
oncopyselection,
|
|
130
264
|
// 选区注释回调。
|
|
@@ -141,10 +275,10 @@
|
|
|
141
275
|
let selectedText = $state('')
|
|
142
276
|
// 选区工具条显示开关。
|
|
143
277
|
let selectionToolbarVisible = $state(false)
|
|
144
|
-
//
|
|
145
|
-
let
|
|
278
|
+
// 选区工具条当前展开的子菜单,统一管理避免多个面板互相覆盖。
|
|
279
|
+
let activeSelectionMenu = $state<SelectionMenuKind | null>(null)
|
|
146
280
|
// 文档头部标题只有在正文首个标题滚出可视区后才显示,避免双标题并排出现。
|
|
147
|
-
let showPinnedTitle = $state(
|
|
281
|
+
let showPinnedTitle = $state(false)
|
|
148
282
|
// 选区工具条在滚动容器中的定位坐标。
|
|
149
283
|
let toolbarPosition = $state<SelectionToolbarPosition>({
|
|
150
284
|
top: 0,
|
|
@@ -152,12 +286,33 @@
|
|
|
152
286
|
placement: 'top',
|
|
153
287
|
alignment: 'center',
|
|
154
288
|
})
|
|
289
|
+
// 选区工具条自身 DOM,用于根据真实尺寸修正贴边位置。
|
|
290
|
+
let selectionToolbarEl = $state<HTMLDivElement | null>(null)
|
|
291
|
+
// 当前展开菜单对应的触发按钮,用来把面板锚定到具体按钮下方/上方。
|
|
292
|
+
let activeSelectionMenuTrigger = $state<HTMLElement | null>(null)
|
|
293
|
+
// 菜单面板相对工具条的水平锚点。
|
|
294
|
+
let selectionMenuLeft = $state(0)
|
|
295
|
+
// 菜单面板在锚点处的对齐方式,避免宽面板越过正文边界。
|
|
296
|
+
let selectionMenuAlignment = $state<'left' | 'center' | 'right'>('center')
|
|
155
297
|
// documentCopied 只负责顶部复制按钮的瞬时反馈,不和正文内容状态混用。
|
|
156
298
|
let documentCopied = $state(false)
|
|
157
299
|
// copyFeedbackTimer 用来保证连续点击复制时,成功态能按最后一次操作重新计时。
|
|
158
|
-
let copyFeedbackTimer:
|
|
300
|
+
let copyFeedbackTimer: number | undefined = $state()
|
|
159
301
|
// 每个代码块的运行状态和预览结果,key 为 codeBlockId。
|
|
160
302
|
let codePreviews = $state<Record<string, CodePreviewState>>({})
|
|
303
|
+
// selectionFormatState 跟随真实 DOM 选区,负责驱动按钮按下态与下拉默认值。
|
|
304
|
+
let selectionFormatState = $state<SelectionFormatState>({
|
|
305
|
+
...DEFAULT_SELECTION_FORMAT_STATE,
|
|
306
|
+
})
|
|
307
|
+
// linkDraft 只在链接弹层里暂存输入值,避免每次打开都丢掉正在编辑的链接。
|
|
308
|
+
let linkDraft = $state('')
|
|
309
|
+
// 真实尺寸修正只需要排队一帧,避免反复触发 handleSelectionChange 形成抖动。
|
|
310
|
+
let selectionToolbarMeasurePending = false
|
|
311
|
+
// 选区刷新统一合并到同一帧,避免 selectionchange / mouseup / blur 连续触发时抖动。
|
|
312
|
+
let selectionRefreshFrame: number | undefined
|
|
313
|
+
let selectionRefreshNeedsRemeasure = false
|
|
314
|
+
// 浏览器在滚动到底部或切换焦点时会短暂给出空选区,这里延迟一拍再关闭工具条。
|
|
315
|
+
let selectionToolbarCloseTimer: number | undefined
|
|
161
316
|
|
|
162
317
|
// code 类型产物通常只有裸代码文本,这里统一包成 fenced block 进入同一条渲染链路。
|
|
163
318
|
const documentContent = $derived(
|
|
@@ -182,16 +337,35 @@
|
|
|
182
337
|
const resolvedRewriteActions = $derived(
|
|
183
338
|
resolveRewriteActions(rewriteActions, onrewrite),
|
|
184
339
|
)
|
|
340
|
+
// 新版工具条支持 paragraph / heading1-4,优先走细粒度回调,避免把旧接口误当成新接口调用。
|
|
341
|
+
const richBlockFormattingEnabled = $derived(Boolean(onapplyblockstyle))
|
|
342
|
+
// 旧版 heading / bullet 回调仍然保留,用于兼容外部还没迁移的调用方。
|
|
343
|
+
const legacyBlockFormattingEnabled = $derived(
|
|
344
|
+
Boolean(onapplyblockformat) && !onapplyblockstyle,
|
|
345
|
+
)
|
|
346
|
+
// 这里统一判断是否存在任意块级格式能力,方便控制分隔线和浮层显隐。
|
|
347
|
+
const anyBlockFormattingEnabled = $derived(
|
|
348
|
+
richBlockFormattingEnabled || legacyBlockFormattingEnabled,
|
|
349
|
+
)
|
|
185
350
|
// selectionToolsEnabled 统一判断选区工具条是否值得出现,避免正文只读展示时还露出空浮层。
|
|
186
351
|
const selectionToolsEnabled = $derived(
|
|
187
352
|
[
|
|
188
353
|
onrewrite,
|
|
189
|
-
|
|
354
|
+
anyBlockFormattingEnabled,
|
|
190
355
|
onapplyinlineformat,
|
|
356
|
+
onapplyalignment,
|
|
357
|
+
onapplylink,
|
|
358
|
+
onapplycolor,
|
|
191
359
|
oncopyselection,
|
|
192
360
|
onannotation,
|
|
193
361
|
].some(Boolean),
|
|
194
362
|
)
|
|
363
|
+
// 当前段落样式的展示文案,直接来自 `selectionFormatState`,避免按钮标题和下拉选中值不同步。
|
|
364
|
+
const activeBlockFormatOption = $derived(
|
|
365
|
+
BLOCK_FORMAT_OPTIONS.find(
|
|
366
|
+
option => option.value === selectionFormatState.blockFormat,
|
|
367
|
+
) ?? BLOCK_FORMAT_OPTIONS[0],
|
|
368
|
+
)
|
|
195
369
|
// readerDocumentClass 只负责正文文章区域,不和外层容器类名混用。
|
|
196
370
|
const readerDocumentClass = $derived(
|
|
197
371
|
cn(
|
|
@@ -259,6 +433,33 @@
|
|
|
259
433
|
if (copyFeedbackTimer) {
|
|
260
434
|
window.clearTimeout(copyFeedbackTimer)
|
|
261
435
|
}
|
|
436
|
+
|
|
437
|
+
if (selectionRefreshFrame) {
|
|
438
|
+
window.cancelAnimationFrame(selectionRefreshFrame)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (selectionToolbarCloseTimer) {
|
|
442
|
+
window.clearTimeout(selectionToolbarCloseTimer)
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
$effect(() => {
|
|
448
|
+
if (typeof document === 'undefined' || !previewHost || !selectionToolsEnabled) {
|
|
449
|
+
return
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const handleDocumentSelectionChange = (): void => {
|
|
453
|
+
queueSelectionRefresh()
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
document.addEventListener('selectionchange', handleDocumentSelectionChange)
|
|
457
|
+
|
|
458
|
+
return () => {
|
|
459
|
+
document.removeEventListener(
|
|
460
|
+
'selectionchange',
|
|
461
|
+
handleDocumentSelectionChange,
|
|
462
|
+
)
|
|
262
463
|
}
|
|
263
464
|
})
|
|
264
465
|
|
|
@@ -605,7 +806,6 @@ ${safeCode}
|
|
|
605
806
|
const markdownHtml = parseMarkdown(result.content, {
|
|
606
807
|
enableHighlight,
|
|
607
808
|
showCopyButton: false,
|
|
608
|
-
showRunButton: false,
|
|
609
809
|
breaks,
|
|
610
810
|
})
|
|
611
811
|
|
|
@@ -629,10 +829,323 @@ ${safeCode}
|
|
|
629
829
|
return escapePreviewText(value).replace(/\n/g, ' ')
|
|
630
830
|
}
|
|
631
831
|
|
|
832
|
+
function getSelectionAnchorElement(selection: Selection): HTMLElement | null {
|
|
833
|
+
const anchorNode = selection.anchorNode
|
|
834
|
+
if (!anchorNode) {
|
|
835
|
+
return null
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return anchorNode instanceof HTMLElement
|
|
839
|
+
? anchorNode
|
|
840
|
+
: anchorNode.parentElement
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
function getClosestBlockElement(element: HTMLElement | null): HTMLElement | null {
|
|
844
|
+
if (!element || !previewHost) {
|
|
845
|
+
return null
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const block = element.closest('p, h1, h2, h3, h4, h5, h6, li')
|
|
849
|
+
return block instanceof HTMLElement && previewHost.contains(block)
|
|
850
|
+
? block
|
|
851
|
+
: null
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function readComputedInlineState(element: HTMLElement | null): Pick<
|
|
855
|
+
SelectionFormatState,
|
|
856
|
+
'bold' | 'italic' | 'strike' | 'underline'
|
|
857
|
+
> {
|
|
858
|
+
if (!element || typeof window === 'undefined') {
|
|
859
|
+
return {
|
|
860
|
+
bold: false,
|
|
861
|
+
italic: false,
|
|
862
|
+
strike: false,
|
|
863
|
+
underline: false,
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const style = window.getComputedStyle(element)
|
|
868
|
+
const fontWeight = Number.parseInt(style.fontWeight, 10)
|
|
869
|
+
const decoration = `${style.textDecorationLine} ${style.textDecoration}`
|
|
870
|
+
.toLowerCase()
|
|
871
|
+
|
|
872
|
+
return {
|
|
873
|
+
bold: Number.isNaN(fontWeight)
|
|
874
|
+
? ['bold', 'bolder'].includes(style.fontWeight.toLowerCase())
|
|
875
|
+
: fontWeight >= 600,
|
|
876
|
+
italic:
|
|
877
|
+
style.fontStyle === 'italic' || style.fontStyle.startsWith('oblique'),
|
|
878
|
+
strike: decoration.includes('line-through'),
|
|
879
|
+
underline: decoration.includes('underline'),
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
function readBlockFormat(element: HTMLElement | null): MarkdownBlockStyleKind {
|
|
884
|
+
const tagName = getClosestBlockElement(element)?.tagName.toLowerCase()
|
|
885
|
+
|
|
886
|
+
if (tagName === 'h1') {
|
|
887
|
+
return 'heading1'
|
|
888
|
+
}
|
|
889
|
+
if (tagName === 'h2') {
|
|
890
|
+
return 'heading2'
|
|
891
|
+
}
|
|
892
|
+
if (tagName === 'h3') {
|
|
893
|
+
return 'heading3'
|
|
894
|
+
}
|
|
895
|
+
if (tagName === 'h4') {
|
|
896
|
+
return 'heading4'
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return 'paragraph'
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function normalizeTextAlign(value: string | null | undefined): MarkdownTextAlignKind | null {
|
|
903
|
+
const normalized = value?.trim().toLowerCase()
|
|
904
|
+
if (!normalized) {
|
|
905
|
+
return null
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (normalized === 'start') {
|
|
909
|
+
return 'left'
|
|
910
|
+
}
|
|
911
|
+
if (normalized === 'end') {
|
|
912
|
+
return 'right'
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
return normalized === 'center'
|
|
916
|
+
|| normalized === 'right'
|
|
917
|
+
|| normalized === 'justify'
|
|
918
|
+
|| normalized === 'left'
|
|
919
|
+
? normalized
|
|
920
|
+
: null
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function readAlignment(element: HTMLElement | null): MarkdownTextAlignKind {
|
|
924
|
+
const block = getClosestBlockElement(element)
|
|
925
|
+
if (!block || typeof window === 'undefined') {
|
|
926
|
+
return 'left'
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// 对齐样式可能挂在外层 `<hai-align>` 容器上,单读 block 的 inline style 会丢失真实状态。
|
|
930
|
+
const alignHost = block.closest<HTMLElement>('.hai-md-align-block') || block
|
|
931
|
+
const computedAlign = normalizeTextAlign(
|
|
932
|
+
window.getComputedStyle(alignHost).textAlign,
|
|
933
|
+
)
|
|
934
|
+
const attributeAlignCandidate
|
|
935
|
+
= alignHost.dataset.haiAlign
|
|
936
|
+
|| alignHost.getAttribute('align')
|
|
937
|
+
|| block.getAttribute('align')
|
|
938
|
+
const attributeAlign = normalizeTextAlign(
|
|
939
|
+
attributeAlignCandidate,
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
return computedAlign || attributeAlign || 'left'
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function readSelectionFormatState(selection: Selection): SelectionFormatState {
|
|
946
|
+
const anchorElement = getSelectionAnchorElement(selection)
|
|
947
|
+
const colorHost = anchorElement?.closest<HTMLElement>('[data-hai-color], [data-hai-bg]')
|
|
948
|
+
const linkHost = anchorElement?.closest<HTMLAnchorElement>('a[href]')
|
|
949
|
+
const codeHost = anchorElement?.closest<HTMLElement>('code')
|
|
950
|
+
const highlightHost = anchorElement?.closest<HTMLElement>('mark')
|
|
951
|
+
const inlineState = readComputedInlineState(anchorElement)
|
|
952
|
+
const hasHighlight = Boolean((highlightHost && previewHost?.contains(highlightHost)) || colorHost?.dataset.haiBg?.trim())
|
|
953
|
+
const textColor = colorHost?.dataset.haiColor?.trim()
|
|
954
|
+
|| anchorElement?.closest<HTMLElement>('[data-hai-color]')?.dataset.haiColor
|
|
955
|
+
|| null
|
|
956
|
+
const backgroundColor = colorHost?.dataset.haiBg?.trim()
|
|
957
|
+
|| anchorElement?.closest<HTMLElement>('[data-hai-bg]')?.dataset.haiBg
|
|
958
|
+
|| null
|
|
959
|
+
|
|
960
|
+
return {
|
|
961
|
+
blockFormat: readBlockFormat(anchorElement),
|
|
962
|
+
alignment: readAlignment(anchorElement),
|
|
963
|
+
bold: inlineState.bold,
|
|
964
|
+
strike: inlineState.strike,
|
|
965
|
+
italic: inlineState.italic,
|
|
966
|
+
underline: inlineState.underline,
|
|
967
|
+
highlight: hasHighlight,
|
|
968
|
+
code: Boolean(codeHost && previewHost?.contains(codeHost)),
|
|
969
|
+
linkHref:
|
|
970
|
+
linkHost && previewHost?.contains(linkHost)
|
|
971
|
+
? (linkHost.getAttribute('href') ?? '')
|
|
972
|
+
: '',
|
|
973
|
+
textColor,
|
|
974
|
+
backgroundColor,
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function readPreviewSelectionState(): PreviewSelectionState | null {
|
|
979
|
+
if (typeof window === 'undefined' || !previewHost) {
|
|
980
|
+
return null
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const selection = window.getSelection()
|
|
984
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
985
|
+
return null
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
const anchorNode = selection.anchorNode
|
|
989
|
+
const focusNode = selection.focusNode
|
|
990
|
+
if (
|
|
991
|
+
!anchorNode
|
|
992
|
+
|| !focusNode
|
|
993
|
+
|| !previewHost.contains(anchorNode)
|
|
994
|
+
|| !previewHost.contains(focusNode)
|
|
995
|
+
) {
|
|
996
|
+
return null
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
const text = selection.toString().trim()
|
|
1000
|
+
if (!text) {
|
|
1001
|
+
return null
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return {
|
|
1005
|
+
selection,
|
|
1006
|
+
range: selection.getRangeAt(0),
|
|
1007
|
+
text,
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
function clearPendingSelectionToolbarClose(): void {
|
|
1012
|
+
if (typeof window === 'undefined' || !selectionToolbarCloseTimer) {
|
|
1013
|
+
return
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
window.clearTimeout(selectionToolbarCloseTimer)
|
|
1017
|
+
selectionToolbarCloseTimer = undefined
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
function scheduleSelectionToolbarClose(): void {
|
|
1021
|
+
if (typeof window === 'undefined') {
|
|
1022
|
+
closeSelectionToolbar()
|
|
1023
|
+
return
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
if (!selectionToolbarVisible) {
|
|
1027
|
+
closeSelectionToolbar()
|
|
1028
|
+
return
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
clearPendingSelectionToolbarClose()
|
|
1032
|
+
selectionToolbarCloseTimer = window.setTimeout(() => {
|
|
1033
|
+
selectionToolbarCloseTimer = undefined
|
|
1034
|
+
if (!readPreviewSelectionState()) {
|
|
1035
|
+
closeSelectionToolbar()
|
|
1036
|
+
}
|
|
1037
|
+
}, 120)
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function queueSelectionRefresh(remeasured = false): void {
|
|
1041
|
+
if (typeof window === 'undefined') {
|
|
1042
|
+
return
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
selectionRefreshNeedsRemeasure ||= remeasured
|
|
1046
|
+
if (selectionRefreshFrame) {
|
|
1047
|
+
return
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
selectionRefreshFrame = window.requestAnimationFrame(() => {
|
|
1051
|
+
const nextRemeasured = selectionRefreshNeedsRemeasure
|
|
1052
|
+
selectionRefreshFrame = undefined
|
|
1053
|
+
selectionRefreshNeedsRemeasure = false
|
|
1054
|
+
handleSelectionChange(nextRemeasured)
|
|
1055
|
+
})
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function estimateSelectionMenuWidth(menu: SelectionMenuKind): number {
|
|
1059
|
+
if (menu === 'color' || menu === 'link') {
|
|
1060
|
+
return 256
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
if (menu === 'rewrite') {
|
|
1064
|
+
return 320
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
return 288
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function updateSelectionMenuAnchor(menu: SelectionMenuKind): void {
|
|
1071
|
+
if (!selectionToolbarEl || !activeSelectionMenuTrigger) {
|
|
1072
|
+
selectionMenuLeft = 0
|
|
1073
|
+
selectionMenuAlignment = 'center'
|
|
1074
|
+
return
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const toolbarWidth = Math.max(
|
|
1078
|
+
selectionToolbarEl.offsetWidth,
|
|
1079
|
+
selectionToolbarEl.clientWidth,
|
|
1080
|
+
)
|
|
1081
|
+
const triggerCenter
|
|
1082
|
+
= activeSelectionMenuTrigger.offsetLeft
|
|
1083
|
+
+ activeSelectionMenuTrigger.offsetWidth / 2
|
|
1084
|
+
const estimatedHalfWidth = Math.min(
|
|
1085
|
+
estimateSelectionMenuWidth(menu) / 2,
|
|
1086
|
+
Math.max(112, (toolbarWidth - 16) / 2),
|
|
1087
|
+
)
|
|
1088
|
+
const minCenter = 8 + estimatedHalfWidth
|
|
1089
|
+
const maxCenter = Math.max(minCenter, toolbarWidth - 8 - estimatedHalfWidth)
|
|
1090
|
+
|
|
1091
|
+
if (triggerCenter <= minCenter) {
|
|
1092
|
+
selectionMenuLeft = 0
|
|
1093
|
+
selectionMenuAlignment = 'left'
|
|
1094
|
+
return
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (triggerCenter >= maxCenter) {
|
|
1098
|
+
selectionMenuLeft = toolbarWidth
|
|
1099
|
+
selectionMenuAlignment = 'right'
|
|
1100
|
+
return
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
selectionMenuLeft = triggerCenter
|
|
1104
|
+
selectionMenuAlignment = 'center'
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function scheduleSelectionToolbarMeasurement(): void {
|
|
1108
|
+
if (
|
|
1109
|
+
typeof window === 'undefined'
|
|
1110
|
+
|| selectionToolbarMeasurePending
|
|
1111
|
+
|| !selectionToolbarVisible
|
|
1112
|
+
) {
|
|
1113
|
+
return
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
selectionToolbarMeasurePending = true
|
|
1117
|
+
window.requestAnimationFrame(() => {
|
|
1118
|
+
selectionToolbarMeasurePending = false
|
|
1119
|
+
if (selectionToolbarVisible) {
|
|
1120
|
+
handleSelectionChange(true)
|
|
1121
|
+
}
|
|
1122
|
+
})
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function toggleSelectionMenu(menu: SelectionMenuKind, event?: MouseEvent): void {
|
|
1126
|
+
const opening = activeSelectionMenu !== menu
|
|
1127
|
+
activeSelectionMenu = opening ? menu : null
|
|
1128
|
+
activeSelectionMenuTrigger = opening && event?.currentTarget instanceof HTMLElement
|
|
1129
|
+
? event.currentTarget
|
|
1130
|
+
: null
|
|
1131
|
+
if (opening) {
|
|
1132
|
+
updateSelectionMenuAnchor(menu)
|
|
1133
|
+
}
|
|
1134
|
+
if (opening && menu === 'link') {
|
|
1135
|
+
linkDraft = selectionFormatState.linkHref || 'https://'
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
632
1139
|
function closeSelectionToolbar(): void {
|
|
1140
|
+
clearPendingSelectionToolbarClose()
|
|
633
1141
|
selectionToolbarVisible = false
|
|
634
|
-
|
|
1142
|
+
activeSelectionMenu = null
|
|
1143
|
+
activeSelectionMenuTrigger = null
|
|
1144
|
+
selectionMenuLeft = 0
|
|
1145
|
+
selectionMenuAlignment = 'center'
|
|
635
1146
|
selectedText = ''
|
|
1147
|
+
linkDraft = ''
|
|
1148
|
+
selectionFormatState = { ...DEFAULT_SELECTION_FORMAT_STATE }
|
|
636
1149
|
}
|
|
637
1150
|
|
|
638
1151
|
/**
|
|
@@ -683,9 +1196,8 @@ ${safeCode}
|
|
|
683
1196
|
return
|
|
684
1197
|
}
|
|
685
1198
|
|
|
686
|
-
const firstHeading
|
|
687
|
-
'[data-heading-id]'
|
|
688
|
-
)
|
|
1199
|
+
const firstHeading
|
|
1200
|
+
= previewHost.querySelector<HTMLElement>('[data-heading-id]')
|
|
689
1201
|
if (!firstHeading) {
|
|
690
1202
|
showPinnedTitle = true
|
|
691
1203
|
return
|
|
@@ -700,7 +1212,7 @@ ${safeCode}
|
|
|
700
1212
|
syncActiveHeadingFromScroll()
|
|
701
1213
|
syncPinnedTitleVisibility()
|
|
702
1214
|
if (selectionToolbarVisible) {
|
|
703
|
-
|
|
1215
|
+
queueSelectionRefresh(true)
|
|
704
1216
|
}
|
|
705
1217
|
ondocumentscroll?.(event)
|
|
706
1218
|
}
|
|
@@ -724,7 +1236,7 @@ ${safeCode}
|
|
|
724
1236
|
* 选区工具条依赖真实 DOM 选区范围,因此只在 selection 落在当前正文容器内时显示。
|
|
725
1237
|
* 一旦内容刷新或滚动位置变化,就主动关闭,避免把旧选区动作误用到新内容上。
|
|
726
1238
|
*/
|
|
727
|
-
function handleSelectionChange(): void {
|
|
1239
|
+
function handleSelectionChange(remeasured = false): void {
|
|
728
1240
|
if (
|
|
729
1241
|
!selectionToolsEnabled
|
|
730
1242
|
|| typeof window === 'undefined'
|
|
@@ -734,79 +1246,70 @@ ${safeCode}
|
|
|
734
1246
|
return
|
|
735
1247
|
}
|
|
736
1248
|
|
|
737
|
-
|
|
738
|
-
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
739
|
-
closeSelectionToolbar()
|
|
740
|
-
return
|
|
741
|
-
}
|
|
1249
|
+
clearPendingSelectionToolbarClose()
|
|
742
1250
|
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
!anchorNode
|
|
747
|
-
|| !focusNode
|
|
748
|
-
|| !previewHost.contains(anchorNode)
|
|
749
|
-
|| !previewHost.contains(focusNode)
|
|
750
|
-
) {
|
|
751
|
-
closeSelectionToolbar()
|
|
1251
|
+
const previewSelection = readPreviewSelectionState()
|
|
1252
|
+
if (!previewSelection) {
|
|
1253
|
+
scheduleSelectionToolbarClose()
|
|
752
1254
|
return
|
|
753
1255
|
}
|
|
754
1256
|
|
|
755
|
-
const text =
|
|
756
|
-
if (!text) {
|
|
757
|
-
closeSelectionToolbar()
|
|
758
|
-
return
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
const range = selection.getRangeAt(0)
|
|
1257
|
+
const { selection, range, text } = previewSelection
|
|
762
1258
|
const rect = range.getBoundingClientRect()
|
|
763
1259
|
const hostRect = editorScrollHost.getBoundingClientRect()
|
|
764
1260
|
// 浮层尺寸在首次渲染前拿不到精确高度,这里用稳定的经验值决定上下避让方向,避免直接盖住选中文本。
|
|
765
|
-
const estimatedToolbarHeight =
|
|
1261
|
+
const estimatedToolbarHeight = 60
|
|
766
1262
|
const offset = 12
|
|
767
1263
|
const topSpace = rect.top - hostRect.top
|
|
768
1264
|
const bottomSpace = hostRect.bottom - rect.bottom
|
|
769
|
-
const placement
|
|
770
|
-
= topSpace >= estimatedToolbarHeight + offset
|
|
1265
|
+
const placement: SelectionToolbarPosition['placement']
|
|
1266
|
+
= topSpace >= estimatedToolbarHeight + offset
|
|
1267
|
+
|| bottomSpace < estimatedToolbarHeight
|
|
771
1268
|
? 'top'
|
|
772
1269
|
: 'bottom'
|
|
773
1270
|
const center = rect.left - hostRect.left + rect.width / 2
|
|
774
1271
|
const horizontalPadding = 16
|
|
1272
|
+
const measuredToolbarHalfWidth = selectionToolbarEl
|
|
1273
|
+
? selectionToolbarEl.offsetWidth / 2
|
|
1274
|
+
: 320
|
|
775
1275
|
const estimatedToolbarHalfWidth = Math.min(
|
|
776
|
-
|
|
777
|
-
Math.max(
|
|
778
|
-
132,
|
|
779
|
-
(editorScrollHost.clientWidth - horizontalPadding * 2) / 2,
|
|
780
|
-
),
|
|
1276
|
+
Math.max(132, measuredToolbarHalfWidth),
|
|
1277
|
+
Math.max(132, (editorScrollHost.clientWidth - horizontalPadding * 2) / 2),
|
|
781
1278
|
)
|
|
782
1279
|
const minCenter = horizontalPadding + estimatedToolbarHalfWidth
|
|
783
1280
|
const maxCenter = editorScrollHost.clientWidth - minCenter
|
|
784
|
-
const alignment
|
|
1281
|
+
const alignment: SelectionToolbarPosition['alignment']
|
|
785
1282
|
= center <= minCenter
|
|
786
1283
|
? 'left'
|
|
787
1284
|
: center >= maxCenter
|
|
788
1285
|
? 'right'
|
|
789
1286
|
: 'center'
|
|
790
|
-
const toolbarLeft
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
? editorScrollHost.scrollTop + rect.top - hostRect.top - estimatedToolbarHeight - offset
|
|
799
|
-
: editorScrollHost.scrollTop + rect.bottom - hostRect.top + offset
|
|
1287
|
+
const toolbarLeft = alignment === 'left'
|
|
1288
|
+
? horizontalPadding
|
|
1289
|
+
: alignment === 'right'
|
|
1290
|
+
? editorScrollHost.clientWidth - horizontalPadding
|
|
1291
|
+
: center
|
|
1292
|
+
const toolbarTop = placement === 'top'
|
|
1293
|
+
? editorScrollHost.scrollTop + rect.top - hostRect.top - estimatedToolbarHeight - offset
|
|
1294
|
+
: editorScrollHost.scrollTop + rect.bottom - hostRect.top + offset
|
|
800
1295
|
|
|
801
1296
|
selectedText = text
|
|
802
1297
|
selectionToolbarVisible = true
|
|
803
|
-
|
|
1298
|
+
selectionFormatState = readSelectionFormatState(selection)
|
|
804
1299
|
toolbarPosition = {
|
|
805
1300
|
top: Math.max(12, toolbarTop),
|
|
806
1301
|
left: Math.max(horizontalPadding, toolbarLeft),
|
|
807
1302
|
placement,
|
|
808
1303
|
alignment,
|
|
809
1304
|
}
|
|
1305
|
+
|
|
1306
|
+
if (activeSelectionMenu) {
|
|
1307
|
+
updateSelectionMenuAnchor(activeSelectionMenu)
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
if (!remeasured) {
|
|
1311
|
+
scheduleSelectionToolbarMeasurement()
|
|
1312
|
+
}
|
|
810
1313
|
}
|
|
811
1314
|
|
|
812
1315
|
async function applyRewrite(actionId: string): Promise<void> {
|
|
@@ -814,7 +1317,8 @@ ${safeCode}
|
|
|
814
1317
|
return
|
|
815
1318
|
}
|
|
816
1319
|
|
|
817
|
-
|
|
1320
|
+
activeSelectionMenu = null
|
|
1321
|
+
activeSelectionMenuTrigger = null
|
|
818
1322
|
await onrewrite({
|
|
819
1323
|
actionId,
|
|
820
1324
|
selectedText,
|
|
@@ -825,26 +1329,63 @@ ${safeCode}
|
|
|
825
1329
|
|
|
826
1330
|
function applyBlockFormat(kind: MarkdownBlockFormatKind): void {
|
|
827
1331
|
onapplyblockformat?.(kind)
|
|
828
|
-
|
|
1332
|
+
activeSelectionMenu = null
|
|
1333
|
+
activeSelectionMenuTrigger = null
|
|
1334
|
+
queueSelectionRefresh()
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
function applyBlockStyle(kind: MarkdownBlockStyleKind): void {
|
|
1338
|
+
onapplyblockstyle?.(kind)
|
|
1339
|
+
activeSelectionMenu = null
|
|
1340
|
+
activeSelectionMenuTrigger = null
|
|
1341
|
+
queueSelectionRefresh()
|
|
829
1342
|
}
|
|
830
1343
|
|
|
831
1344
|
function applyInlineFormat(kind: MarkdownInlineFormatKind): void {
|
|
832
1345
|
onapplyinlineformat?.(kind)
|
|
833
|
-
|
|
1346
|
+
queueSelectionRefresh()
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
function applyAlignment(kind: MarkdownTextAlignKind): void {
|
|
1350
|
+
onapplyalignment?.(kind)
|
|
1351
|
+
activeSelectionMenu = null
|
|
1352
|
+
activeSelectionMenuTrigger = null
|
|
1353
|
+
queueSelectionRefresh()
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
function applyLink(): void {
|
|
1357
|
+
onapplylink?.(linkDraft.trim() || null)
|
|
1358
|
+
activeSelectionMenu = null
|
|
1359
|
+
activeSelectionMenuTrigger = null
|
|
1360
|
+
queueSelectionRefresh()
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function removeLink(): void {
|
|
1364
|
+
onapplylink?.(null)
|
|
1365
|
+
activeSelectionMenu = null
|
|
1366
|
+
activeSelectionMenuTrigger = null
|
|
1367
|
+
queueSelectionRefresh()
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
function applyColor(request: MarkdownColorFormatRequest): void {
|
|
1371
|
+
onapplycolor?.(request)
|
|
1372
|
+
queueSelectionRefresh()
|
|
834
1373
|
}
|
|
835
1374
|
|
|
836
1375
|
async function copySelection(): Promise<void> {
|
|
837
1376
|
await oncopyselection?.()
|
|
838
|
-
|
|
1377
|
+
activeSelectionMenu = null
|
|
1378
|
+
activeSelectionMenuTrigger = null
|
|
839
1379
|
}
|
|
840
1380
|
|
|
841
1381
|
async function annotateSelection(): Promise<void> {
|
|
842
1382
|
await onannotation?.()
|
|
843
|
-
|
|
1383
|
+
activeSelectionMenu = null
|
|
1384
|
+
activeSelectionMenuTrigger = null
|
|
844
1385
|
}
|
|
845
1386
|
|
|
846
1387
|
function handlePreviewMouseUp(): void {
|
|
847
|
-
|
|
1388
|
+
queueSelectionRefresh()
|
|
848
1389
|
onpreviewmouseup?.()
|
|
849
1390
|
}
|
|
850
1391
|
|
|
@@ -853,7 +1394,7 @@ ${safeCode}
|
|
|
853
1394
|
}
|
|
854
1395
|
|
|
855
1396
|
function handlePreviewBlur(): void {
|
|
856
|
-
|
|
1397
|
+
queueSelectionRefresh(true)
|
|
857
1398
|
onpreviewblur?.()
|
|
858
1399
|
}
|
|
859
1400
|
</script>
|
|
@@ -893,6 +1434,7 @@ ${safeCode}
|
|
|
893
1434
|
type='button'
|
|
894
1435
|
class='hai-ai-doc-toolbar-icon'
|
|
895
1436
|
aria-label={uiM('markdown_undo')}
|
|
1437
|
+
title={`${uiM('markdown_undo')} (Ctrl/Cmd+Z)`}
|
|
896
1438
|
disabled={undoDisabled}
|
|
897
1439
|
onclick={onundo}
|
|
898
1440
|
>
|
|
@@ -909,6 +1451,7 @@ ${safeCode}
|
|
|
909
1451
|
type='button'
|
|
910
1452
|
class='hai-ai-doc-toolbar-icon'
|
|
911
1453
|
aria-label={uiM('markdown_redo')}
|
|
1454
|
+
title={`${uiM('markdown_redo')} (Ctrl/Cmd+Shift+Z)`}
|
|
912
1455
|
disabled={redoDisabled}
|
|
913
1456
|
onclick={onredo}
|
|
914
1457
|
>
|
|
@@ -951,12 +1494,12 @@ ${safeCode}
|
|
|
951
1494
|
</button>
|
|
952
1495
|
|
|
953
1496
|
<AiDocumentDownloadMenu
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1497
|
+
{content}
|
|
1498
|
+
{title}
|
|
1499
|
+
{sourceKind}
|
|
1500
|
+
{codeLanguage}
|
|
958
1501
|
actions={downloadActions}
|
|
959
|
-
|
|
1502
|
+
{ondownload}
|
|
960
1503
|
showLabel={true}
|
|
961
1504
|
iconOnly={false}
|
|
962
1505
|
triggerTitle={uiM('markdown_download')}
|
|
@@ -1046,14 +1589,7 @@ ${safeCode}
|
|
|
1046
1589
|
class='hai-ai-doc-scroll'
|
|
1047
1590
|
onclick={handleClick}
|
|
1048
1591
|
onscroll={handleDocumentScroll}
|
|
1049
|
-
onkeyup={handleSelectionChange}
|
|
1050
|
-
onfocusout={() => {
|
|
1051
|
-
if (typeof window !== 'undefined') {
|
|
1052
|
-
window.setTimeout(() => {
|
|
1053
|
-
handleSelectionChange()
|
|
1054
|
-
}, 0)
|
|
1055
|
-
}
|
|
1056
|
-
}}
|
|
1592
|
+
onkeyup={() => handleSelectionChange()}
|
|
1057
1593
|
>
|
|
1058
1594
|
{#if selectionToolbarVisible}
|
|
1059
1595
|
<div
|
|
@@ -1063,178 +1599,503 @@ ${safeCode}
|
|
|
1063
1599
|
style={`top:${toolbarPosition.top}px; left:${toolbarPosition.left}px;`}
|
|
1064
1600
|
>
|
|
1065
1601
|
<div
|
|
1066
|
-
class='hai-ai-doc-selection-
|
|
1067
|
-
role='toolbar'
|
|
1068
|
-
tabindex='-1'
|
|
1069
|
-
onmousedown={event => event.preventDefault()}
|
|
1602
|
+
class='hai-ai-doc-selection-chrome'
|
|
1070
1603
|
>
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1079
|
-
<path
|
|
1080
|
-
d='M12 3.25a.75.75 0 0 1 .72.55l1.06 3.62 3.63 1.06a.75.75 0 0 1 0 1.44l-3.63 1.06-1.06 3.63a.75.75 0 0 1-1.44 0l-1.06-3.63-3.63-1.06a.75.75 0 0 1 0-1.44l3.63-1.06 1.06-3.62a.75.75 0 0 1 .72-.55Zm6.5 11.5a.75.75 0 0 1 .72.55l.42 1.43 1.43.42a.75.75 0 0 1 0 1.44l-1.43.42-.42 1.43a.75.75 0 0 1-1.44 0l-.42-1.43-1.43-.42a.75.75 0 0 1 0-1.44l1.43-.42.42-1.43a.75.75 0 0 1 .72-.55Z'
|
|
1081
|
-
></path>
|
|
1082
|
-
</svg>
|
|
1083
|
-
<span>{uiM('markdown_rewrite')}</span>
|
|
1084
|
-
</button>
|
|
1085
|
-
{/if}
|
|
1086
|
-
|
|
1087
|
-
{#if onapplyblockformat}
|
|
1604
|
+
<div
|
|
1605
|
+
bind:this={selectionToolbarEl}
|
|
1606
|
+
class='hai-ai-doc-selection-toolbar'
|
|
1607
|
+
role='toolbar'
|
|
1608
|
+
tabindex='-1'
|
|
1609
|
+
onmousedown={event => event.preventDefault()}
|
|
1610
|
+
>
|
|
1088
1611
|
{#if onrewrite}
|
|
1089
|
-
<
|
|
1612
|
+
<button
|
|
1613
|
+
type='button'
|
|
1614
|
+
class={cn(
|
|
1615
|
+
'hai-ai-doc-selection-chip',
|
|
1616
|
+
activeSelectionMenu === 'rewrite'
|
|
1617
|
+
? 'hai-ai-doc-selection-chip--active'
|
|
1618
|
+
: '',
|
|
1619
|
+
)}
|
|
1620
|
+
disabled={rewritePending}
|
|
1621
|
+
onclick={event => toggleSelectionMenu('rewrite', event)}
|
|
1622
|
+
>
|
|
1623
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1624
|
+
<path
|
|
1625
|
+
d='M12 3.25a.75.75 0 0 1 .72.55l1.06 3.62 3.63 1.06a.75.75 0 0 1 0 1.44l-3.63 1.06-1.06 3.63a.75.75 0 0 1-1.44 0l-1.06-3.63-3.63-1.06a.75.75 0 0 1 0-1.44l3.63-1.06 1.06-3.62a.75.75 0 0 1 .72-.55Zm6.5 11.5a.75.75 0 0 1 .72.55l.42 1.43 1.43.42a.75.75 0 0 1 0 1.44l-1.43.42-.42 1.43a.75.75 0 0 1-1.44 0l-.42-1.43-1.43-.42a.75.75 0 0 1 0-1.44l1.43-.42.42-1.43a.75.75 0 0 1 .72-.55Z'
|
|
1626
|
+
></path>
|
|
1627
|
+
</svg>
|
|
1628
|
+
<span>{uiM('markdown_rewrite')}</span>
|
|
1629
|
+
</button>
|
|
1090
1630
|
{/if}
|
|
1091
|
-
<button
|
|
1092
|
-
type='button'
|
|
1093
|
-
class='hai-ai-doc-selection-btn'
|
|
1094
|
-
title={uiM('markdown_format_heading')}
|
|
1095
|
-
onclick={() => applyBlockFormat('heading')}
|
|
1096
|
-
>
|
|
1097
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1098
|
-
<path
|
|
1099
|
-
d='M5 5.25a.75.75 0 0 1 .75.75V11h6.5V6a.75.75 0 0 1 1.5 0v12a.75.75 0 0 1-1.5 0v-5.5h-6.5V18a.75.75 0 0 1-1.5 0V6A.75.75 0 0 1 5 5.25Zm11.25 2.5a.75.75 0 0 1 0 1.5h3a.75.75 0 0 1 0 1.5H18.5v8.5a.75.75 0 0 1-1.5 0v-8.5h-.75a.75.75 0 0 1 0-1.5h3Z'
|
|
1100
|
-
></path>
|
|
1101
|
-
</svg>
|
|
1102
|
-
</button>
|
|
1103
|
-
<button
|
|
1104
|
-
type='button'
|
|
1105
|
-
class='hai-ai-doc-selection-btn'
|
|
1106
|
-
title={uiM('markdown_format_bullet')}
|
|
1107
|
-
onclick={() => applyBlockFormat('bullet')}
|
|
1108
|
-
>
|
|
1109
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1110
|
-
<path
|
|
1111
|
-
d='M6.25 7.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Z'
|
|
1112
|
-
></path>
|
|
1113
|
-
</svg>
|
|
1114
|
-
</button>
|
|
1115
|
-
{/if}
|
|
1116
1631
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1632
|
+
{#if richBlockFormattingEnabled}
|
|
1633
|
+
{#if onrewrite}
|
|
1634
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1635
|
+
{/if}
|
|
1636
|
+
<button
|
|
1637
|
+
type='button'
|
|
1638
|
+
class={cn(
|
|
1639
|
+
'hai-ai-doc-selection-trigger',
|
|
1640
|
+
activeSelectionMenu === 'block'
|
|
1641
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1642
|
+
: '',
|
|
1643
|
+
)}
|
|
1644
|
+
title={uiM('markdown_format_heading')}
|
|
1645
|
+
onclick={event => toggleSelectionMenu('block', event)}
|
|
1646
|
+
>
|
|
1647
|
+
<span class='hai-ai-doc-selection-trigger-label'>
|
|
1648
|
+
{activeBlockFormatOption.shortLabel}
|
|
1649
|
+
</span>
|
|
1650
|
+
<svg
|
|
1651
|
+
viewBox='0 0 24 24'
|
|
1652
|
+
aria-hidden='true'
|
|
1653
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1654
|
+
>
|
|
1655
|
+
<path
|
|
1656
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1657
|
+
></path>
|
|
1658
|
+
</svg>
|
|
1659
|
+
</button>
|
|
1660
|
+
{:else if legacyBlockFormattingEnabled}
|
|
1661
|
+
{#if onrewrite}
|
|
1662
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1663
|
+
{/if}
|
|
1664
|
+
<button
|
|
1665
|
+
type='button'
|
|
1666
|
+
class='hai-ai-doc-selection-btn'
|
|
1667
|
+
title={uiM('markdown_format_heading')}
|
|
1668
|
+
onclick={() => applyBlockFormat('heading')}
|
|
1669
|
+
>
|
|
1670
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1671
|
+
<path
|
|
1672
|
+
d='M5 5.25a.75.75 0 0 1 .75.75V11h6.5V6a.75.75 0 0 1 1.5 0v12a.75.75 0 0 1-1.5 0v-5.5h-6.5V18a.75.75 0 0 1-1.5 0V6A.75.75 0 0 1 5 5.25Zm11.25 2.5a.75.75 0 0 1 0 1.5h3a.75.75 0 0 1 0 1.5H18.5v8.5a.75.75 0 0 1-1.5 0v-8.5h-.75a.75.75 0 0 1 0-1.5h3Z'
|
|
1673
|
+
></path>
|
|
1674
|
+
</svg>
|
|
1675
|
+
</button>
|
|
1676
|
+
<button
|
|
1677
|
+
type='button'
|
|
1678
|
+
class='hai-ai-doc-selection-btn'
|
|
1679
|
+
title={uiM('markdown_format_bullet')}
|
|
1680
|
+
onclick={() => applyBlockFormat('bullet')}
|
|
1681
|
+
>
|
|
1682
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1683
|
+
<path
|
|
1684
|
+
d='M6.25 7.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Z'
|
|
1685
|
+
></path>
|
|
1686
|
+
</svg>
|
|
1687
|
+
</button>
|
|
1688
|
+
{/if}
|
|
1689
|
+
|
|
1690
|
+
{#if onapplyalignment}
|
|
1691
|
+
{#if anyBlockFormattingEnabled || onrewrite}
|
|
1692
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1693
|
+
{/if}
|
|
1694
|
+
<button
|
|
1695
|
+
type='button'
|
|
1696
|
+
class={cn(
|
|
1697
|
+
'hai-ai-doc-selection-trigger',
|
|
1698
|
+
activeSelectionMenu === 'align'
|
|
1699
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1700
|
+
: '',
|
|
1701
|
+
)}
|
|
1702
|
+
title={uiM('markdown_align')}
|
|
1703
|
+
onclick={event => toggleSelectionMenu('align', event)}
|
|
1704
|
+
>
|
|
1705
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1706
|
+
{#if selectionFormatState.alignment === 'center'}
|
|
1707
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm2.75 4.75a.75.75 0 0 1 .75-.75h7a.75.75 0 0 1 0 1.5h-7a.75.75 0 0 1-.75-.75Zm-2 4.75a.75.75 0 0 1 .75-.75h11a.75.75 0 0 1 0 1.5h-11a.75.75 0 0 1-.75-.75Z'></path>
|
|
1708
|
+
{:else if selectionFormatState.alignment === 'right'}
|
|
1709
|
+
<path d='M5.75 5.5a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5H5.75Zm4 4.75a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Zm-4 4.75a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5H5.75Z'></path>
|
|
1710
|
+
{:else if selectionFormatState.alignment === 'justify'}
|
|
1711
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 11Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 15.75Z'></path>
|
|
1712
|
+
{:else}
|
|
1713
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm0 4.75a.75.75 0 0 1 .75-.75h8.5a.75.75 0 0 1 0 1.5h-8.5A.75.75 0 0 1 5 11Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 15.75Z'></path>
|
|
1714
|
+
{/if}
|
|
1715
|
+
</svg>
|
|
1716
|
+
<svg
|
|
1717
|
+
viewBox='0 0 24 24'
|
|
1718
|
+
aria-hidden='true'
|
|
1719
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1720
|
+
>
|
|
1721
|
+
<path
|
|
1722
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1723
|
+
></path>
|
|
1724
|
+
</svg>
|
|
1725
|
+
</button>
|
|
1726
|
+
{/if}
|
|
1727
|
+
|
|
1728
|
+
{#if onapplyinlineformat || onapplylink || onapplycolor}
|
|
1729
|
+
{#if anyBlockFormattingEnabled || onapplyalignment || onrewrite}
|
|
1730
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1731
|
+
{/if}
|
|
1120
1732
|
{/if}
|
|
1121
|
-
<button
|
|
1122
|
-
type='button'
|
|
1123
|
-
class='hai-ai-doc-selection-btn'
|
|
1124
|
-
title={uiM('markdown_format_bold')}
|
|
1125
|
-
onclick={() => applyInlineFormat('bold')}
|
|
1126
|
-
>
|
|
1127
|
-
<strong>B</strong>
|
|
1128
|
-
</button>
|
|
1129
|
-
<button
|
|
1130
|
-
type='button'
|
|
1131
|
-
class='hai-ai-doc-selection-btn'
|
|
1132
|
-
title={uiM('markdown_format_strike')}
|
|
1133
|
-
onclick={() => applyInlineFormat('strike')}
|
|
1134
|
-
>
|
|
1135
|
-
S
|
|
1136
|
-
</button>
|
|
1137
|
-
<button
|
|
1138
|
-
type='button'
|
|
1139
|
-
class='hai-ai-doc-selection-btn'
|
|
1140
|
-
title={uiM('markdown_format_italic')}
|
|
1141
|
-
onclick={() => applyInlineFormat('italic')}
|
|
1142
|
-
>
|
|
1143
|
-
<em>I</em>
|
|
1144
|
-
</button>
|
|
1145
|
-
<button
|
|
1146
|
-
type='button'
|
|
1147
|
-
class='hai-ai-doc-selection-btn'
|
|
1148
|
-
title={uiM('markdown_format_underline')}
|
|
1149
|
-
onclick={() => applyInlineFormat('underline')}
|
|
1150
|
-
>
|
|
1151
|
-
U
|
|
1152
|
-
</button>
|
|
1153
|
-
<button
|
|
1154
|
-
type='button'
|
|
1155
|
-
class='hai-ai-doc-selection-btn'
|
|
1156
|
-
title={uiM('markdown_format_link')}
|
|
1157
|
-
onclick={() => applyInlineFormat('link')}
|
|
1158
|
-
>
|
|
1159
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1160
|
-
<path
|
|
1161
|
-
d='M7.78 15.72a3.75 3.75 0 0 1 0-5.3l2.47-2.47a3.75 3.75 0 0 1 5.3 5.3l-.97.98a.75.75 0 0 1-1.06-1.06l.98-.97a2.25 2.25 0 0 0-3.19-3.19l-2.47 2.47a2.25 2.25 0 1 0 3.18 3.18l.49-.49a.75.75 0 0 1 1.06 1.06l-.49.49a3.75 3.75 0 0 1-5.3 0Zm8.44-7.44a.75.75 0 0 1 0 1.06l-8 8a.75.75 0 0 1-1.06-1.06l8-8a.75.75 0 0 1 1.06 0Z'
|
|
1162
|
-
></path>
|
|
1163
|
-
</svg>
|
|
1164
|
-
</button>
|
|
1165
|
-
<button
|
|
1166
|
-
type='button'
|
|
1167
|
-
class='hai-ai-doc-selection-btn'
|
|
1168
|
-
title={uiM('markdown_format_code')}
|
|
1169
|
-
onclick={() => applyInlineFormat('code')}
|
|
1170
|
-
>
|
|
1171
|
-
</>
|
|
1172
|
-
</button>
|
|
1173
|
-
<button
|
|
1174
|
-
type='button'
|
|
1175
|
-
class='hai-ai-doc-selection-btn'
|
|
1176
|
-
title={uiM('markdown_format_highlight')}
|
|
1177
|
-
onclick={() => applyInlineFormat('highlight')}
|
|
1178
|
-
>
|
|
1179
|
-
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1180
|
-
</button>
|
|
1181
|
-
{/if}
|
|
1182
1733
|
|
|
1183
|
-
{#if oncopyselection || onannotation}
|
|
1184
1734
|
{#if onapplyinlineformat}
|
|
1185
|
-
<
|
|
1735
|
+
<button
|
|
1736
|
+
type='button'
|
|
1737
|
+
class={cn(
|
|
1738
|
+
'hai-ai-doc-selection-btn',
|
|
1739
|
+
selectionFormatState.bold
|
|
1740
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1741
|
+
: '',
|
|
1742
|
+
)}
|
|
1743
|
+
title={uiM('markdown_format_bold')}
|
|
1744
|
+
onclick={() => applyInlineFormat('bold')}
|
|
1745
|
+
>
|
|
1746
|
+
<strong>B</strong>
|
|
1747
|
+
</button>
|
|
1748
|
+
<button
|
|
1749
|
+
type='button'
|
|
1750
|
+
class={cn(
|
|
1751
|
+
'hai-ai-doc-selection-btn',
|
|
1752
|
+
selectionFormatState.strike
|
|
1753
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1754
|
+
: '',
|
|
1755
|
+
)}
|
|
1756
|
+
title={uiM('markdown_format_strike')}
|
|
1757
|
+
onclick={() => applyInlineFormat('strike')}
|
|
1758
|
+
>
|
|
1759
|
+
S
|
|
1760
|
+
</button>
|
|
1761
|
+
<button
|
|
1762
|
+
type='button'
|
|
1763
|
+
class={cn(
|
|
1764
|
+
'hai-ai-doc-selection-btn',
|
|
1765
|
+
selectionFormatState.italic
|
|
1766
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1767
|
+
: '',
|
|
1768
|
+
)}
|
|
1769
|
+
title={uiM('markdown_format_italic')}
|
|
1770
|
+
onclick={() => applyInlineFormat('italic')}
|
|
1771
|
+
>
|
|
1772
|
+
<em>I</em>
|
|
1773
|
+
</button>
|
|
1774
|
+
<button
|
|
1775
|
+
type='button'
|
|
1776
|
+
class={cn(
|
|
1777
|
+
'hai-ai-doc-selection-btn',
|
|
1778
|
+
selectionFormatState.underline
|
|
1779
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1780
|
+
: '',
|
|
1781
|
+
)}
|
|
1782
|
+
title={uiM('markdown_format_underline')}
|
|
1783
|
+
onclick={() => applyInlineFormat('underline')}
|
|
1784
|
+
>
|
|
1785
|
+
U
|
|
1786
|
+
</button>
|
|
1186
1787
|
{/if}
|
|
1187
|
-
{/if}
|
|
1188
1788
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1789
|
+
{#if onapplylink || onapplyinlineformat}
|
|
1790
|
+
<button
|
|
1791
|
+
type='button'
|
|
1792
|
+
class={cn(
|
|
1793
|
+
'hai-ai-doc-selection-btn',
|
|
1794
|
+
selectionFormatState.linkHref
|
|
1795
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1796
|
+
: '',
|
|
1797
|
+
activeSelectionMenu === 'link'
|
|
1798
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1799
|
+
: '',
|
|
1800
|
+
)}
|
|
1801
|
+
title={uiM('markdown_format_link')}
|
|
1802
|
+
onclick={event =>
|
|
1803
|
+
onapplylink
|
|
1804
|
+
? toggleSelectionMenu('link', event)
|
|
1805
|
+
: applyInlineFormat('link')}
|
|
1806
|
+
>
|
|
1807
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1808
|
+
<path
|
|
1809
|
+
d='M7.78 15.72a3.75 3.75 0 0 1 0-5.3l2.47-2.47a3.75 3.75 0 0 1 5.3 5.3l-.97.98a.75.75 0 0 1-1.06-1.06l.98-.97a2.25 2.25 0 0 0-3.19-3.19l-2.47 2.47a2.25 2.25 0 1 0 3.18 3.18l.49-.49a.75.75 0 0 1 1.06 1.06l-.49.49a3.75 3.75 0 0 1-5.3 0Zm8.44-7.44a.75.75 0 0 1 0 1.06l-8 8a.75.75 0 0 1-1.06-1.06l8-8a.75.75 0 0 1 1.06 0Z'
|
|
1810
|
+
></path>
|
|
1811
|
+
</svg>
|
|
1812
|
+
</button>
|
|
1813
|
+
{/if}
|
|
1203
1814
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1815
|
+
{#if onapplyinlineformat}
|
|
1816
|
+
<button
|
|
1817
|
+
type='button'
|
|
1818
|
+
class={cn(
|
|
1819
|
+
'hai-ai-doc-selection-btn',
|
|
1820
|
+
selectionFormatState.code
|
|
1821
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1822
|
+
: '',
|
|
1823
|
+
)}
|
|
1824
|
+
title={uiM('markdown_format_code')}
|
|
1825
|
+
onclick={() => applyInlineFormat('code')}
|
|
1826
|
+
>
|
|
1827
|
+
</>
|
|
1828
|
+
</button>
|
|
1829
|
+
<button
|
|
1830
|
+
type='button'
|
|
1831
|
+
class={cn(
|
|
1832
|
+
'hai-ai-doc-selection-btn',
|
|
1833
|
+
selectionFormatState.highlight
|
|
1834
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1835
|
+
: '',
|
|
1836
|
+
)}
|
|
1837
|
+
title={uiM('markdown_format_highlight')}
|
|
1838
|
+
onclick={() => applyInlineFormat('highlight')}
|
|
1839
|
+
>
|
|
1840
|
+
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1841
|
+
</button>
|
|
1842
|
+
{/if}
|
|
1219
1843
|
|
|
1220
|
-
|
|
1221
|
-
<div
|
|
1222
|
-
class='hai-ai-doc-rewrite-menu'
|
|
1223
|
-
role='menu'
|
|
1224
|
-
tabindex='-1'
|
|
1225
|
-
onmousedown={event => event.preventDefault()}
|
|
1226
|
-
>
|
|
1227
|
-
{#each resolvedRewriteActions as action}
|
|
1844
|
+
{#if onapplycolor}
|
|
1228
1845
|
<button
|
|
1229
1846
|
type='button'
|
|
1230
|
-
|
|
1231
|
-
|
|
1847
|
+
class={cn(
|
|
1848
|
+
'hai-ai-doc-selection-trigger',
|
|
1849
|
+
activeSelectionMenu === 'color'
|
|
1850
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1851
|
+
: '',
|
|
1852
|
+
)}
|
|
1853
|
+
style={`--hai-ai-doc-current-color:${selectionFormatState.textColor ?? '#0f172a'};`}
|
|
1854
|
+
title={uiM('markdown_text_color')}
|
|
1855
|
+
onclick={event => toggleSelectionMenu('color', event)}
|
|
1232
1856
|
>
|
|
1233
|
-
|
|
1857
|
+
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1858
|
+
<svg
|
|
1859
|
+
viewBox='0 0 24 24'
|
|
1860
|
+
aria-hidden='true'
|
|
1861
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1862
|
+
>
|
|
1863
|
+
<path
|
|
1864
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1865
|
+
></path>
|
|
1866
|
+
</svg>
|
|
1234
1867
|
</button>
|
|
1235
|
-
{/
|
|
1868
|
+
{/if}
|
|
1869
|
+
|
|
1870
|
+
{#if oncopyselection || onannotation}
|
|
1871
|
+
{#if onapplyinlineformat || onapplylink || onapplycolor}
|
|
1872
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1873
|
+
{/if}
|
|
1874
|
+
{/if}
|
|
1875
|
+
|
|
1876
|
+
{#if oncopyselection}
|
|
1877
|
+
<button
|
|
1878
|
+
type='button'
|
|
1879
|
+
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1880
|
+
title={uiM('markdown_copy_selection')}
|
|
1881
|
+
onclick={copySelection}
|
|
1882
|
+
>
|
|
1883
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1884
|
+
<path
|
|
1885
|
+
d='M8.75 4.25A2.75 2.75 0 0 0 6 7v8.25A2.75 2.75 0 0 0 8.75 18h7.5A2.75 2.75 0 0 0 19 15.25V7a2.75 2.75 0 0 0-2.75-2.75h-7.5Zm-4 3A2.75 2.75 0 0 1 7.5 4.5a.75.75 0 0 0 0-1.5A4.25 4.25 0 0 0 3.25 7.25v8.5A4.25 4.25 0 0 0 7.5 20a.75.75 0 0 0 0-1.5 2.75 2.75 0 0 1-2.75-2.75v-8.5Z'
|
|
1886
|
+
></path>
|
|
1887
|
+
</svg>
|
|
1888
|
+
<span>{uiM('markdown_copy_selection')}</span>
|
|
1889
|
+
</button>
|
|
1890
|
+
{/if}
|
|
1891
|
+
|
|
1892
|
+
{#if onannotation}
|
|
1893
|
+
<button
|
|
1894
|
+
type='button'
|
|
1895
|
+
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1896
|
+
title={uiM('markdown_annotation')}
|
|
1897
|
+
onclick={annotateSelection}
|
|
1898
|
+
>
|
|
1899
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1900
|
+
<path
|
|
1901
|
+
d='M6.75 4.25A2.75 2.75 0 0 0 4 7v7.75A2.75 2.75 0 0 0 6.75 17.5h1.72l2.3 2.01a1.75 1.75 0 0 0 2.3 0l2.3-2.01h1.88A2.75 2.75 0 0 0 20 14.75V7a2.75 2.75 0 0 0-2.75-2.75H6.75Zm1.5 4a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Zm0 3.5A.75.75 0 0 1 9 11h4a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Z'
|
|
1902
|
+
></path>
|
|
1903
|
+
</svg>
|
|
1904
|
+
</button>
|
|
1905
|
+
{/if}
|
|
1236
1906
|
</div>
|
|
1237
|
-
|
|
1907
|
+
|
|
1908
|
+
{#if activeSelectionMenu === 'rewrite' && resolvedRewriteActions.length > 0}
|
|
1909
|
+
<div
|
|
1910
|
+
class='hai-ai-doc-rewrite-menu'
|
|
1911
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
1912
|
+
role='menu'
|
|
1913
|
+
tabindex='-1'
|
|
1914
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
1915
|
+
onmousedown={event => event.preventDefault()}
|
|
1916
|
+
>
|
|
1917
|
+
{#each resolvedRewriteActions as action}
|
|
1918
|
+
<button
|
|
1919
|
+
type='button'
|
|
1920
|
+
class='hai-ai-doc-rewrite-menu-btn'
|
|
1921
|
+
disabled={rewritePending}
|
|
1922
|
+
onclick={() => applyRewrite(action.id)}
|
|
1923
|
+
>
|
|
1924
|
+
{action.label}
|
|
1925
|
+
</button>
|
|
1926
|
+
{/each}
|
|
1927
|
+
</div>
|
|
1928
|
+
{:else if activeSelectionMenu === 'block' && richBlockFormattingEnabled}
|
|
1929
|
+
<div
|
|
1930
|
+
class='hai-ai-doc-selection-panel'
|
|
1931
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
1932
|
+
role='menu'
|
|
1933
|
+
tabindex='-1'
|
|
1934
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
1935
|
+
onmousedown={event => event.preventDefault()}
|
|
1936
|
+
>
|
|
1937
|
+
{#each BLOCK_FORMAT_OPTIONS as option}
|
|
1938
|
+
<button
|
|
1939
|
+
type='button'
|
|
1940
|
+
class={cn(
|
|
1941
|
+
'hai-ai-doc-selection-menu-btn',
|
|
1942
|
+
selectionFormatState.blockFormat === option.value
|
|
1943
|
+
? 'hai-ai-doc-selection-menu-btn--active'
|
|
1944
|
+
: '',
|
|
1945
|
+
)}
|
|
1946
|
+
onclick={() => applyBlockStyle(option.value)}
|
|
1947
|
+
>
|
|
1948
|
+
<span class='hai-ai-doc-selection-menu-label'>
|
|
1949
|
+
<span class='hai-ai-doc-selection-menu-short'>
|
|
1950
|
+
{option.shortLabel}
|
|
1951
|
+
</span>
|
|
1952
|
+
<span>{uiM(option.labelKey)}</span>
|
|
1953
|
+
</span>
|
|
1954
|
+
{#if selectionFormatState.blockFormat === option.value}
|
|
1955
|
+
<span class='hai-ai-doc-selection-menu-check'>✓</span>
|
|
1956
|
+
{/if}
|
|
1957
|
+
</button>
|
|
1958
|
+
{/each}
|
|
1959
|
+
</div>
|
|
1960
|
+
{:else if activeSelectionMenu === 'align' && onapplyalignment}
|
|
1961
|
+
<div
|
|
1962
|
+
class='hai-ai-doc-selection-panel'
|
|
1963
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
1964
|
+
role='menu'
|
|
1965
|
+
tabindex='-1'
|
|
1966
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
1967
|
+
onmousedown={event => event.preventDefault()}
|
|
1968
|
+
>
|
|
1969
|
+
{#each ALIGN_OPTIONS as option}
|
|
1970
|
+
<button
|
|
1971
|
+
type='button'
|
|
1972
|
+
class={cn(
|
|
1973
|
+
'hai-ai-doc-selection-menu-btn',
|
|
1974
|
+
selectionFormatState.alignment === option.value
|
|
1975
|
+
? 'hai-ai-doc-selection-menu-btn--active'
|
|
1976
|
+
: '',
|
|
1977
|
+
)}
|
|
1978
|
+
onclick={() => applyAlignment(option.value)}
|
|
1979
|
+
>
|
|
1980
|
+
<span>{uiM(option.labelKey)}</span>
|
|
1981
|
+
{#if selectionFormatState.alignment === option.value}
|
|
1982
|
+
<span class='hai-ai-doc-selection-menu-check'>✓</span>
|
|
1983
|
+
{/if}
|
|
1984
|
+
</button>
|
|
1985
|
+
{/each}
|
|
1986
|
+
</div>
|
|
1987
|
+
{:else if activeSelectionMenu === 'link' && onapplylink}
|
|
1988
|
+
<div
|
|
1989
|
+
class='hai-ai-doc-selection-panel hai-ai-doc-selection-panel--link'
|
|
1990
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
1991
|
+
role='dialog'
|
|
1992
|
+
aria-label={uiM('markdown_link_dialog_label')}
|
|
1993
|
+
tabindex='-1'
|
|
1994
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
1995
|
+
onmousedown={event => event.preventDefault()}
|
|
1996
|
+
>
|
|
1997
|
+
<input
|
|
1998
|
+
class='hai-ai-doc-selection-input'
|
|
1999
|
+
bind:value={linkDraft}
|
|
2000
|
+
aria-label={uiM('markdown_link_input_label')}
|
|
2001
|
+
placeholder={uiM('markdown_link_placeholder')}
|
|
2002
|
+
onkeydown={(event) => {
|
|
2003
|
+
if (event.key === 'Enter') {
|
|
2004
|
+
event.preventDefault()
|
|
2005
|
+
applyLink()
|
|
2006
|
+
}
|
|
2007
|
+
}}
|
|
2008
|
+
/>
|
|
2009
|
+
<div class='hai-ai-doc-selection-panel-actions'>
|
|
2010
|
+
<button
|
|
2011
|
+
type='button'
|
|
2012
|
+
class='hai-ai-doc-selection-panel-btn hai-ai-doc-selection-panel-btn--primary'
|
|
2013
|
+
onclick={applyLink}
|
|
2014
|
+
>
|
|
2015
|
+
{uiM('markdown_link_apply')}
|
|
2016
|
+
</button>
|
|
2017
|
+
<button
|
|
2018
|
+
type='button'
|
|
2019
|
+
class='hai-ai-doc-selection-panel-btn'
|
|
2020
|
+
disabled={!selectionFormatState.linkHref}
|
|
2021
|
+
onclick={removeLink}
|
|
2022
|
+
>
|
|
2023
|
+
{uiM('markdown_link_remove')}
|
|
2024
|
+
</button>
|
|
2025
|
+
</div>
|
|
2026
|
+
</div>
|
|
2027
|
+
{:else if activeSelectionMenu === 'color' && onapplycolor}
|
|
2028
|
+
<div
|
|
2029
|
+
class='hai-ai-doc-selection-panel hai-ai-doc-selection-panel--color'
|
|
2030
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2031
|
+
role='dialog'
|
|
2032
|
+
aria-label={uiM('markdown_color_dialog_label')}
|
|
2033
|
+
tabindex='-1'
|
|
2034
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2035
|
+
onmousedown={event => event.preventDefault()}
|
|
2036
|
+
>
|
|
2037
|
+
<div class='hai-ai-doc-color-group'>
|
|
2038
|
+
<div class='hai-ai-doc-color-group-title'>
|
|
2039
|
+
{uiM('markdown_text_color')}
|
|
2040
|
+
</div>
|
|
2041
|
+
<div class='hai-ai-doc-color-grid'>
|
|
2042
|
+
{#each TEXT_COLOR_PRESETS as color}
|
|
2043
|
+
<button
|
|
2044
|
+
type='button'
|
|
2045
|
+
class={cn(
|
|
2046
|
+
'hai-ai-doc-color-swatch',
|
|
2047
|
+
selectionFormatState.textColor === color
|
|
2048
|
+
? 'hai-ai-doc-color-swatch--active'
|
|
2049
|
+
: '',
|
|
2050
|
+
)}
|
|
2051
|
+
title={color}
|
|
2052
|
+
onclick={() =>
|
|
2053
|
+
applyColor({ target: 'text', value: color })}
|
|
2054
|
+
>
|
|
2055
|
+
<span style={`background:${color};`}></span>
|
|
2056
|
+
</button>
|
|
2057
|
+
{/each}
|
|
2058
|
+
</div>
|
|
2059
|
+
</div>
|
|
2060
|
+
<div class='hai-ai-doc-color-group'>
|
|
2061
|
+
<div class='hai-ai-doc-color-group-title'>
|
|
2062
|
+
{uiM('markdown_background_color')}
|
|
2063
|
+
</div>
|
|
2064
|
+
<div class='hai-ai-doc-color-grid'>
|
|
2065
|
+
{#each BACKGROUND_COLOR_PRESETS as color}
|
|
2066
|
+
<button
|
|
2067
|
+
type='button'
|
|
2068
|
+
class={cn(
|
|
2069
|
+
'hai-ai-doc-color-swatch',
|
|
2070
|
+
selectionFormatState.backgroundColor === color
|
|
2071
|
+
? 'hai-ai-doc-color-swatch--active'
|
|
2072
|
+
: '',
|
|
2073
|
+
)}
|
|
2074
|
+
title={color}
|
|
2075
|
+
onclick={() =>
|
|
2076
|
+
applyColor({
|
|
2077
|
+
target: 'background',
|
|
2078
|
+
value: color,
|
|
2079
|
+
})}
|
|
2080
|
+
>
|
|
2081
|
+
<span style={`background:${color};`}></span>
|
|
2082
|
+
</button>
|
|
2083
|
+
{/each}
|
|
2084
|
+
</div>
|
|
2085
|
+
</div>
|
|
2086
|
+
<button
|
|
2087
|
+
type='button'
|
|
2088
|
+
class='hai-ai-doc-selection-panel-btn'
|
|
2089
|
+
onclick={() => {
|
|
2090
|
+
applyColor({ target: 'text', value: null })
|
|
2091
|
+
applyColor({ target: 'background', value: null })
|
|
2092
|
+
}}
|
|
2093
|
+
>
|
|
2094
|
+
{uiM('markdown_reset_default')}
|
|
2095
|
+
</button>
|
|
2096
|
+
</div>
|
|
2097
|
+
{/if}
|
|
2098
|
+
</div>
|
|
1238
2099
|
</div>
|
|
1239
2100
|
{/if}
|
|
1240
2101
|
|
|
@@ -1394,9 +2255,9 @@ ${safeCode}
|
|
|
1394
2255
|
}
|
|
1395
2256
|
|
|
1396
2257
|
.hai-ai-doc-toolbar-icon:not(:disabled):hover,
|
|
1397
|
-
:global(.hai-ai-doc-toolbar-icon:hover),
|
|
2258
|
+
:global(.hai-ai-doc-toolbar-icon:not(:disabled):hover),
|
|
1398
2259
|
.hai-ai-doc-toolbar-pill:not(:disabled):hover,
|
|
1399
|
-
:global(.hai-ai-doc-toolbar-pill:hover),
|
|
2260
|
+
:global(.hai-ai-doc-toolbar-pill:not(:disabled):hover),
|
|
1400
2261
|
.hai-ai-doc-toolbar-action:hover,
|
|
1401
2262
|
.hai-ai-doc-toolbar-close:not(:disabled):hover,
|
|
1402
2263
|
.hai-ai-doc-version-toggle:hover,
|
|
@@ -1407,9 +2268,9 @@ ${safeCode}
|
|
|
1407
2268
|
}
|
|
1408
2269
|
|
|
1409
2270
|
.hai-ai-doc-toolbar-icon:not(:disabled):hover,
|
|
1410
|
-
:global(.hai-ai-doc-toolbar-icon:hover),
|
|
2271
|
+
:global(.hai-ai-doc-toolbar-icon:not(:disabled):hover),
|
|
1411
2272
|
.hai-ai-doc-toolbar-pill:not(:disabled):hover,
|
|
1412
|
-
:global(.hai-ai-doc-toolbar-pill:hover),
|
|
2273
|
+
:global(.hai-ai-doc-toolbar-pill:not(:disabled):hover),
|
|
1413
2274
|
.hai-ai-doc-toolbar-close:not(:disabled):hover {
|
|
1414
2275
|
transform: translateY(-1px);
|
|
1415
2276
|
box-shadow: 0 12px 28px -22px oklch(var(--bc) / 0.36);
|
|
@@ -1420,11 +2281,25 @@ ${safeCode}
|
|
|
1420
2281
|
.hai-ai-doc-toolbar-pill:disabled,
|
|
1421
2282
|
:global(.hai-ai-doc-toolbar-pill:disabled),
|
|
1422
2283
|
.hai-ai-doc-toolbar-close:disabled {
|
|
1423
|
-
opacity: 0.
|
|
2284
|
+
opacity: 0.72;
|
|
2285
|
+
color: oklch(var(--bc) / 0.36);
|
|
2286
|
+
border-color: oklch(var(--bc) / 0.12);
|
|
2287
|
+
background: oklch(var(--b2) / 0.58);
|
|
1424
2288
|
cursor: not-allowed;
|
|
1425
2289
|
box-shadow: none;
|
|
1426
2290
|
}
|
|
1427
2291
|
|
|
2292
|
+
.hai-ai-doc-toolbar-icon:disabled:hover,
|
|
2293
|
+
:global(.hai-ai-doc-toolbar-icon:disabled:hover),
|
|
2294
|
+
.hai-ai-doc-toolbar-pill:disabled:hover,
|
|
2295
|
+
:global(.hai-ai-doc-toolbar-pill:disabled:hover),
|
|
2296
|
+
.hai-ai-doc-toolbar-close:disabled:hover {
|
|
2297
|
+
cursor: not-allowed;
|
|
2298
|
+
transform: none;
|
|
2299
|
+
box-shadow: none;
|
|
2300
|
+
filter: grayscale(0.18);
|
|
2301
|
+
}
|
|
2302
|
+
|
|
1428
2303
|
.hai-ai-doc-toolbar-action,
|
|
1429
2304
|
.hai-ai-doc-version-toggle {
|
|
1430
2305
|
border: 1px solid oklch(var(--bc) / 0.08);
|
|
@@ -1574,7 +2449,8 @@ ${safeCode}
|
|
|
1574
2449
|
min-width: 0;
|
|
1575
2450
|
min-height: 0;
|
|
1576
2451
|
position: relative;
|
|
1577
|
-
z-index:
|
|
2452
|
+
z-index: 2;
|
|
2453
|
+
isolation: isolate;
|
|
1578
2454
|
}
|
|
1579
2455
|
|
|
1580
2456
|
.hai-ai-doc-scroll {
|
|
@@ -1586,47 +2462,66 @@ ${safeCode}
|
|
|
1586
2462
|
|
|
1587
2463
|
.hai-ai-doc-selection-layer {
|
|
1588
2464
|
position: absolute;
|
|
1589
|
-
z-index:
|
|
1590
|
-
display:
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
width: min(max-content, calc(100% - 2rem));
|
|
2465
|
+
z-index: 60;
|
|
2466
|
+
display: block;
|
|
2467
|
+
width: fit-content;
|
|
2468
|
+
max-width: calc(100% - 2rem);
|
|
1594
2469
|
transform: translateX(-50%);
|
|
2470
|
+
transition:
|
|
2471
|
+
top 0.14s cubic-bezier(0.2, 0.85, 0.24, 1),
|
|
2472
|
+
left 0.14s cubic-bezier(0.2, 0.85, 0.24, 1),
|
|
2473
|
+
transform 0.14s cubic-bezier(0.2, 0.85, 0.24, 1);
|
|
1595
2474
|
pointer-events: none;
|
|
1596
2475
|
}
|
|
1597
2476
|
|
|
1598
|
-
.hai-ai-doc-selection-layer[data-placement='top'] {
|
|
1599
|
-
flex-direction: column-reverse;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
2477
|
.hai-ai-doc-selection-layer[data-alignment='left'] {
|
|
1603
|
-
transform:
|
|
2478
|
+
transform: translateX(0);
|
|
2479
|
+
justify-items: start;
|
|
1604
2480
|
}
|
|
1605
2481
|
|
|
1606
2482
|
.hai-ai-doc-selection-layer[data-alignment='right'] {
|
|
1607
2483
|
transform: translateX(-100%);
|
|
2484
|
+
justify-items: end;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
.hai-ai-doc-selection-layer[data-alignment='center'] {
|
|
2488
|
+
justify-items: center;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
.hai-ai-doc-selection-chrome {
|
|
2492
|
+
position: relative;
|
|
2493
|
+
display: inline-grid;
|
|
2494
|
+
width: fit-content;
|
|
2495
|
+
max-width: min(100%, calc(100vw - 2rem));
|
|
1608
2496
|
}
|
|
1609
2497
|
|
|
1610
2498
|
.hai-ai-doc-selection-toolbar {
|
|
1611
2499
|
display: flex;
|
|
1612
2500
|
align-items: center;
|
|
1613
2501
|
gap: 0.25rem;
|
|
1614
|
-
flex-wrap:
|
|
1615
|
-
|
|
2502
|
+
flex-wrap: nowrap;
|
|
2503
|
+
width: fit-content;
|
|
2504
|
+
max-width: calc(100% - 0.75rem);
|
|
2505
|
+
white-space: nowrap;
|
|
1616
2506
|
padding: 0.38rem;
|
|
1617
2507
|
border-radius: 1.2rem;
|
|
1618
|
-
background:
|
|
1619
|
-
|
|
2508
|
+
background-color: rgb(255 255 255 / 0.96);
|
|
2509
|
+
background: color-mix(in srgb, oklch(var(--b1, 1 0 0)) 94%, white 6%);
|
|
2510
|
+
border: 1px solid rgb(148 163 184 / 0.34);
|
|
2511
|
+
border-color: color-mix(in srgb, oklch(var(--bc, 0.22 0 0)) 16%, white 84%);
|
|
1620
2512
|
box-shadow:
|
|
1621
2513
|
0 30px 60px -34px rgb(15 23 42 / 0.28),
|
|
1622
2514
|
0 14px 26px -18px rgb(15 23 42 / 0.16),
|
|
1623
2515
|
0 0 0 1px rgb(255 255 255 / 0.94) inset;
|
|
1624
2516
|
pointer-events: auto;
|
|
1625
2517
|
isolation: isolate;
|
|
2518
|
+
position: relative;
|
|
2519
|
+
z-index: 2;
|
|
1626
2520
|
}
|
|
1627
2521
|
|
|
1628
2522
|
.hai-ai-doc-selection-chip,
|
|
1629
|
-
.hai-ai-doc-selection-btn
|
|
2523
|
+
.hai-ai-doc-selection-btn,
|
|
2524
|
+
.hai-ai-doc-selection-trigger {
|
|
1630
2525
|
min-height: 2.25rem;
|
|
1631
2526
|
border-radius: 0.9rem;
|
|
1632
2527
|
transition:
|
|
@@ -1640,6 +2535,7 @@ ${safeCode}
|
|
|
1640
2535
|
display: inline-flex;
|
|
1641
2536
|
align-items: center;
|
|
1642
2537
|
gap: 0.48rem;
|
|
2538
|
+
flex-shrink: 0;
|
|
1643
2539
|
padding: 0 0.88rem;
|
|
1644
2540
|
border: 1px solid oklch(var(--p) / 0.16);
|
|
1645
2541
|
background: oklch(var(--p) / 0.1);
|
|
@@ -1654,9 +2550,16 @@ ${safeCode}
|
|
|
1654
2550
|
fill: currentColor;
|
|
1655
2551
|
}
|
|
1656
2552
|
|
|
2553
|
+
.hai-ai-doc-selection-chip--active {
|
|
2554
|
+
border-color: oklch(var(--p) / 0.28);
|
|
2555
|
+
background: oklch(var(--p) / 0.16);
|
|
2556
|
+
color: oklch(var(--bc));
|
|
2557
|
+
}
|
|
2558
|
+
|
|
1657
2559
|
.hai-ai-doc-selection-chip:not(:disabled):hover,
|
|
1658
2560
|
.hai-ai-doc-selection-btn:hover,
|
|
1659
|
-
.hai-ai-doc-
|
|
2561
|
+
.hai-ai-doc-selection-trigger:hover,
|
|
2562
|
+
.hai-ai-doc-rewrite-menu-btn:hover {
|
|
1660
2563
|
transform: translateY(-1px);
|
|
1661
2564
|
}
|
|
1662
2565
|
|
|
@@ -1668,6 +2571,7 @@ ${safeCode}
|
|
|
1668
2571
|
.hai-ai-doc-selection-btn {
|
|
1669
2572
|
width: 2.25rem;
|
|
1670
2573
|
min-width: 2.25rem;
|
|
2574
|
+
flex-shrink: 0;
|
|
1671
2575
|
display: inline-flex;
|
|
1672
2576
|
align-items: center;
|
|
1673
2577
|
justify-content: center;
|
|
@@ -1679,21 +2583,61 @@ ${safeCode}
|
|
|
1679
2583
|
}
|
|
1680
2584
|
|
|
1681
2585
|
.hai-ai-doc-selection-btn-wide {
|
|
1682
|
-
|
|
2586
|
+
width: auto;
|
|
2587
|
+
min-width: 4.6rem;
|
|
2588
|
+
gap: 0.42rem;
|
|
2589
|
+
padding: 0 0.74rem;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
.hai-ai-doc-selection-trigger {
|
|
2593
|
+
min-width: 3.4rem;
|
|
2594
|
+
display: inline-flex;
|
|
2595
|
+
align-items: center;
|
|
2596
|
+
gap: 0.34rem;
|
|
2597
|
+
padding: 0 0.66rem;
|
|
2598
|
+
border: 1px solid transparent;
|
|
2599
|
+
background: transparent;
|
|
2600
|
+
color: oklch(var(--bc) / 0.78);
|
|
2601
|
+
cursor: pointer;
|
|
1683
2602
|
}
|
|
1684
2603
|
|
|
1685
|
-
.hai-ai-doc-selection-btn:hover
|
|
2604
|
+
.hai-ai-doc-selection-btn:hover,
|
|
2605
|
+
.hai-ai-doc-selection-trigger:hover {
|
|
1686
2606
|
border-color: oklch(var(--bc) / 0.1);
|
|
1687
2607
|
background: oklch(var(--bc) / 0.045);
|
|
1688
2608
|
color: oklch(var(--bc));
|
|
1689
2609
|
}
|
|
1690
2610
|
|
|
2611
|
+
.hai-ai-doc-selection-btn--active,
|
|
2612
|
+
.hai-ai-doc-selection-trigger--active {
|
|
2613
|
+
border-color: oklch(var(--p) / 0.22);
|
|
2614
|
+
background: oklch(var(--p) / 0.12);
|
|
2615
|
+
color: oklch(var(--bc));
|
|
2616
|
+
}
|
|
2617
|
+
|
|
1691
2618
|
.hai-ai-doc-selection-btn svg {
|
|
1692
2619
|
width: 1rem;
|
|
1693
2620
|
height: 1rem;
|
|
1694
2621
|
fill: currentColor;
|
|
1695
2622
|
}
|
|
1696
2623
|
|
|
2624
|
+
.hai-ai-doc-selection-trigger svg {
|
|
2625
|
+
width: 1rem;
|
|
2626
|
+
height: 1rem;
|
|
2627
|
+
fill: currentColor;
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
.hai-ai-doc-selection-trigger-label {
|
|
2631
|
+
font-weight: 600;
|
|
2632
|
+
line-height: 1;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
.hai-ai-doc-selection-trigger-chevron {
|
|
2636
|
+
width: 0.8rem !important;
|
|
2637
|
+
height: 0.8rem !important;
|
|
2638
|
+
opacity: 0.72;
|
|
2639
|
+
}
|
|
2640
|
+
|
|
1697
2641
|
.hai-ai-doc-selection-divider {
|
|
1698
2642
|
width: 1px;
|
|
1699
2643
|
height: 1.45rem;
|
|
@@ -1705,6 +2649,7 @@ ${safeCode}
|
|
|
1705
2649
|
.hai-ai-doc-selection-highlight-icon {
|
|
1706
2650
|
position: relative;
|
|
1707
2651
|
font-weight: 700;
|
|
2652
|
+
color: var(--hai-ai-doc-current-color, currentColor);
|
|
1708
2653
|
}
|
|
1709
2654
|
|
|
1710
2655
|
.hai-ai-doc-selection-highlight-icon::after {
|
|
@@ -1715,41 +2660,213 @@ ${safeCode}
|
|
|
1715
2660
|
bottom: -0.02rem;
|
|
1716
2661
|
height: 0.36rem;
|
|
1717
2662
|
border-radius: 9999px;
|
|
1718
|
-
background:
|
|
2663
|
+
background: color-mix(
|
|
2664
|
+
in srgb,
|
|
2665
|
+
var(--hai-ai-doc-current-color, oklch(var(--wa, 0.9 0.14 90))) 22%,
|
|
2666
|
+
white 78%
|
|
2667
|
+
);
|
|
1719
2668
|
z-index: -1;
|
|
1720
2669
|
}
|
|
1721
2670
|
|
|
2671
|
+
.hai-ai-doc-selection-panel,
|
|
1722
2672
|
.hai-ai-doc-rewrite-menu {
|
|
1723
|
-
|
|
2673
|
+
position: absolute;
|
|
2674
|
+
left: var(--hai-ai-doc-selection-menu-left, 0px);
|
|
2675
|
+
top: calc(100% + 0.45rem);
|
|
1724
2676
|
display: grid;
|
|
1725
|
-
gap: 0.
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
border:
|
|
2677
|
+
gap: 0.34rem;
|
|
2678
|
+
width: min(18rem, calc(100vw - 2rem));
|
|
2679
|
+
max-width: calc(100vw - 2rem);
|
|
2680
|
+
padding: 0.42rem;
|
|
2681
|
+
border-radius: 1rem;
|
|
2682
|
+
background-color: rgb(255 255 255 / 0.96);
|
|
2683
|
+
background: color-mix(in srgb, oklch(var(--b1, 1 0 0)) 94%, white 6%);
|
|
2684
|
+
border: 1px solid rgb(148 163 184 / 0.3);
|
|
2685
|
+
border-color: color-mix(in srgb, oklch(var(--bc, 0.22 0 0)) 14%, white 86%);
|
|
1730
2686
|
box-shadow:
|
|
1731
|
-
0
|
|
1732
|
-
0
|
|
1733
|
-
0 0 0 1px rgb(255 255 255 / 0.94) inset;
|
|
2687
|
+
0 24px 40px -28px rgb(15 23 42 / 0.25),
|
|
2688
|
+
0 10px 20px -16px rgb(15 23 42 / 0.14);
|
|
1734
2689
|
pointer-events: auto;
|
|
1735
2690
|
isolation: isolate;
|
|
2691
|
+
z-index: 3;
|
|
1736
2692
|
}
|
|
1737
2693
|
|
|
1738
|
-
.hai-ai-doc-rewrite-menu
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2694
|
+
.hai-ai-doc-rewrite-menu {
|
|
2695
|
+
width: fit-content;
|
|
2696
|
+
max-width: min(22rem, calc(100vw - 2rem));
|
|
2697
|
+
grid-template-columns: repeat(auto-fit, minmax(7.2rem, 1fr));
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
.hai-ai-doc-selection-layer[data-placement='bottom'] .hai-ai-doc-selection-panel,
|
|
2701
|
+
.hai-ai-doc-selection-layer[data-placement='bottom'] .hai-ai-doc-rewrite-menu {
|
|
2702
|
+
top: auto;
|
|
2703
|
+
bottom: calc(100% + 0.45rem);
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='left'],
|
|
2707
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='left'] {
|
|
2708
|
+
transform: translateX(0);
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='center'],
|
|
2712
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='center'] {
|
|
2713
|
+
transform: translateX(-50%);
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='right'],
|
|
2717
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='right'] {
|
|
2718
|
+
transform: translateX(-100%);
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
.hai-ai-doc-selection-panel--link,
|
|
2722
|
+
.hai-ai-doc-selection-panel--color {
|
|
2723
|
+
width: min(16rem, calc(100vw - 2rem));
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
.hai-ai-doc-selection-menu-btn,
|
|
2727
|
+
.hai-ai-doc-selection-panel-btn,
|
|
2728
|
+
.hai-ai-doc-rewrite-menu-btn {
|
|
2729
|
+
min-height: 2rem;
|
|
2730
|
+
display: inline-flex;
|
|
2731
|
+
align-items: center;
|
|
2732
|
+
justify-content: space-between;
|
|
2733
|
+
gap: 0.6rem;
|
|
2734
|
+
width: 100%;
|
|
2735
|
+
padding: 0 0.72rem;
|
|
2736
|
+
border-radius: 0.8rem;
|
|
2737
|
+
border: 1px solid oklch(var(--bc) / 0.14);
|
|
2738
|
+
background: color-mix(in srgb, oklch(var(--b1)) 92%, white 8%);
|
|
2739
|
+
color: oklch(var(--bc) / 0.86);
|
|
2740
|
+
font-size: 0.82rem;
|
|
2741
|
+
line-height: 1;
|
|
1745
2742
|
cursor: pointer;
|
|
2743
|
+
transition:
|
|
2744
|
+
background-color 0.14s ease,
|
|
2745
|
+
border-color 0.14s ease,
|
|
2746
|
+
color 0.14s ease,
|
|
2747
|
+
transform 0.14s ease;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
.hai-ai-doc-selection-menu-btn--active,
|
|
2751
|
+
.hai-ai-doc-selection-panel-btn--primary {
|
|
2752
|
+
border-color: oklch(var(--p) / 0.28);
|
|
2753
|
+
background: oklch(var(--p) / 0.12);
|
|
2754
|
+
color: oklch(var(--bc));
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
.hai-ai-doc-selection-menu-btn:hover,
|
|
2758
|
+
.hai-ai-doc-selection-panel-btn:hover,
|
|
2759
|
+
.hai-ai-doc-rewrite-menu-btn:hover:not(:disabled) {
|
|
2760
|
+
border-color: oklch(var(--bc) / 0.22);
|
|
2761
|
+
background: color-mix(in srgb, oklch(var(--b2)) 68%, white 32%);
|
|
2762
|
+
color: oklch(var(--bc));
|
|
2763
|
+
transform: translateY(-1px);
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
.hai-ai-doc-selection-menu-label {
|
|
2767
|
+
display: inline-flex;
|
|
2768
|
+
align-items: center;
|
|
2769
|
+
gap: 0.62rem;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
.hai-ai-doc-selection-menu-short {
|
|
2773
|
+
min-width: 2rem;
|
|
2774
|
+
color: oklch(var(--p) / 0.92);
|
|
2775
|
+
font-weight: 700;
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
.hai-ai-doc-selection-menu-check {
|
|
2779
|
+
color: oklch(var(--p) / 0.88);
|
|
2780
|
+
font-weight: 700;
|
|
1746
2781
|
}
|
|
1747
2782
|
|
|
1748
|
-
.hai-ai-doc-
|
|
2783
|
+
.hai-ai-doc-selection-input {
|
|
2784
|
+
width: 100%;
|
|
2785
|
+
min-height: 2.25rem;
|
|
2786
|
+
padding: 0 0.78rem;
|
|
2787
|
+
border-radius: 0.85rem;
|
|
2788
|
+
border: 1px solid oklch(var(--bc) / 0.16);
|
|
2789
|
+
background: color-mix(in srgb, oklch(var(--b1)) 94%, white 6%);
|
|
2790
|
+
color: oklch(var(--bc));
|
|
2791
|
+
font-size: 0.84rem;
|
|
2792
|
+
outline: none;
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
.hai-ai-doc-selection-input:focus {
|
|
2796
|
+
border-color: oklch(var(--p) / 0.34);
|
|
2797
|
+
box-shadow: 0 0 0 3px oklch(var(--p) / 0.12);
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
.hai-ai-doc-selection-panel-actions {
|
|
2801
|
+
display: flex;
|
|
2802
|
+
gap: 0.4rem;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
.hai-ai-doc-selection-panel-actions .hai-ai-doc-selection-panel-btn {
|
|
2806
|
+
flex: 1 1 0;
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
.hai-ai-doc-selection-panel-btn:disabled,
|
|
2810
|
+
.hai-ai-doc-rewrite-menu-btn:disabled {
|
|
1749
2811
|
opacity: 0.55;
|
|
1750
2812
|
cursor: default;
|
|
1751
2813
|
}
|
|
1752
2814
|
|
|
2815
|
+
.hai-ai-doc-color-group {
|
|
2816
|
+
display: grid;
|
|
2817
|
+
gap: 0.42rem;
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
.hai-ai-doc-color-group-title {
|
|
2821
|
+
font-size: 0.78rem;
|
|
2822
|
+
font-weight: 600;
|
|
2823
|
+
color: oklch(var(--bc) / 0.68);
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
.hai-ai-doc-color-grid {
|
|
2827
|
+
display: grid;
|
|
2828
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
2829
|
+
gap: 0.42rem;
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
.hai-ai-doc-color-swatch {
|
|
2833
|
+
width: 100%;
|
|
2834
|
+
aspect-ratio: 1;
|
|
2835
|
+
display: inline-flex;
|
|
2836
|
+
align-items: center;
|
|
2837
|
+
justify-content: center;
|
|
2838
|
+
padding: 0.18rem;
|
|
2839
|
+
border-radius: 0.7rem;
|
|
2840
|
+
border: 1px solid oklch(var(--bc) / 0.12);
|
|
2841
|
+
background: color-mix(in srgb, oklch(var(--b1)) 92%, white 8%);
|
|
2842
|
+
cursor: pointer;
|
|
2843
|
+
transition:
|
|
2844
|
+
transform 0.14s ease,
|
|
2845
|
+
border-color 0.14s ease,
|
|
2846
|
+
box-shadow 0.14s ease;
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
.hai-ai-doc-color-swatch:hover {
|
|
2850
|
+
transform: translateY(-1px);
|
|
2851
|
+
border-color: oklch(var(--bc) / 0.2);
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
.hai-ai-doc-color-swatch--active {
|
|
2855
|
+
border-color: oklch(var(--p) / 0.34);
|
|
2856
|
+
box-shadow: 0 0 0 3px oklch(var(--p) / 0.12);
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
.hai-ai-doc-color-swatch span {
|
|
2860
|
+
width: 100%;
|
|
2861
|
+
height: 100%;
|
|
2862
|
+
border-radius: 0.5rem;
|
|
2863
|
+
border: 1px solid rgb(15 23 42 / 0.08);
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
.hai-ai-doc-rewrite-menu-btn {
|
|
2867
|
+
justify-content: center;
|
|
2868
|
+
}
|
|
2869
|
+
|
|
1753
2870
|
.hai-markdown {
|
|
1754
2871
|
line-height: 1.9;
|
|
1755
2872
|
color: inherit;
|
|
@@ -1829,6 +2946,10 @@ ${safeCode}
|
|
|
1829
2946
|
margin-bottom: 1em;
|
|
1830
2947
|
}
|
|
1831
2948
|
|
|
2949
|
+
.hai-markdown :global(.hai-md-align-block) {
|
|
2950
|
+
width: 100%;
|
|
2951
|
+
}
|
|
2952
|
+
|
|
1832
2953
|
.hai-markdown :global(a) {
|
|
1833
2954
|
color: oklch(var(--p));
|
|
1834
2955
|
text-decoration: none;
|
|
@@ -1852,6 +2973,23 @@ ${safeCode}
|
|
|
1852
2973
|
color: oklch(var(--bc) / 0.55);
|
|
1853
2974
|
}
|
|
1854
2975
|
|
|
2976
|
+
.hai-markdown :global(u) {
|
|
2977
|
+
text-decoration-thickness: 0.08em;
|
|
2978
|
+
text-underline-offset: 0.14em;
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
.hai-markdown :global(mark) {
|
|
2982
|
+
padding: 0 0.12em;
|
|
2983
|
+
border-radius: 0.25rem;
|
|
2984
|
+
background: oklch(var(--wa, 0.9 0.14 90) / 0.34);
|
|
2985
|
+
color: inherit;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
.hai-markdown :global(.hai-md-inline-style) {
|
|
2989
|
+
border-radius: 0.2rem;
|
|
2990
|
+
padding: 0 0.04em;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
1855
2993
|
.hai-markdown :global(:not(pre) > code) {
|
|
1856
2994
|
padding: 0.2em 0.4em;
|
|
1857
2995
|
margin: 0 0.1em;
|
|
@@ -2203,7 +3341,7 @@ ${safeCode}
|
|
|
2203
3341
|
|
|
2204
3342
|
.hai-ai-doc-selection-toolbar {
|
|
2205
3343
|
max-width: calc(100vw - 2rem);
|
|
2206
|
-
overflow:
|
|
3344
|
+
overflow: hidden;
|
|
2207
3345
|
}
|
|
2208
3346
|
}
|
|
2209
3347
|
</style>
|