@harborclient/sdk 1.0.58 → 1.0.59
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/CodeEditor/index.d.ts +56 -1
- package/dist/components/CodeEditor/index.d.ts.map +1 -1
- package/dist/components/CodeEditor/index.js +280 -2
- package/dist/components/Toolbar/index.d.ts.map +1 -1
- package/dist/components/Toolbar/index.js +9 -2
- package/dist/components/VariableInput/index.d.ts.map +1 -1
- package/dist/components/VariableInput/index.js +53 -14
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CompletionSource } from '@codemirror/autocomplete';
|
|
2
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
2
3
|
import type { ComponentPropsWithoutRef, JSX } from 'react';
|
|
3
4
|
import type { CodeEditorSetup, CodeEditorTheme, Variable } from '../../types.js';
|
|
4
5
|
export { CODE_EDITOR_THEME_OPTIONS } from './themes.js';
|
|
@@ -92,6 +93,56 @@ export interface CodeEditorViewState {
|
|
|
92
93
|
*/
|
|
93
94
|
selection: CodeEditorSelectionRange;
|
|
94
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Selected text range passed to {@link CodeEditorSelectionAction.onSelect}.
|
|
98
|
+
*/
|
|
99
|
+
export interface CodeEditorTextSelection {
|
|
100
|
+
/**
|
|
101
|
+
* Selected document text.
|
|
102
|
+
*/
|
|
103
|
+
text: string;
|
|
104
|
+
/**
|
|
105
|
+
* Start offset (inclusive) in the document.
|
|
106
|
+
*/
|
|
107
|
+
from: number;
|
|
108
|
+
/**
|
|
109
|
+
* End offset (exclusive) in the document.
|
|
110
|
+
*/
|
|
111
|
+
to: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* One action offered in the floating toolbar when the user selects text.
|
|
115
|
+
*/
|
|
116
|
+
export interface CodeEditorSelectionAction {
|
|
117
|
+
/**
|
|
118
|
+
* Stable action id for host routing.
|
|
119
|
+
*/
|
|
120
|
+
id: string;
|
|
121
|
+
/**
|
|
122
|
+
* Visible button label.
|
|
123
|
+
*/
|
|
124
|
+
label: string;
|
|
125
|
+
/**
|
|
126
|
+
* Accessible name for the action button.
|
|
127
|
+
*/
|
|
128
|
+
ariaLabel: string;
|
|
129
|
+
/**
|
|
130
|
+
* Called when the user activates this action on the current selection.
|
|
131
|
+
*/
|
|
132
|
+
onSelect: (selection: CodeEditorTextSelection) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Optional leading icon shown before the action label.
|
|
135
|
+
*/
|
|
136
|
+
icon?: IconDefinition;
|
|
137
|
+
/**
|
|
138
|
+
* Optional shortcut hint shown after the label (for example `Ctrl+L`).
|
|
139
|
+
*/
|
|
140
|
+
shortcutHint?: string;
|
|
141
|
+
/**
|
|
142
|
+
* Optional CodeMirror key binding that triggers this action on the current selection.
|
|
143
|
+
*/
|
|
144
|
+
key?: string;
|
|
145
|
+
}
|
|
95
146
|
export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'onChange' | 'className' | 'id' | 'aria-label' | 'aria-labelledby' | 'aria-invalid' | 'aria-describedby' | 'style'> {
|
|
96
147
|
/**
|
|
97
148
|
* Editor content.
|
|
@@ -172,6 +223,10 @@ export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
172
223
|
* Called when the user presses Enter on a complete slash command line.
|
|
173
224
|
*/
|
|
174
225
|
onSlashCommand?: (trigger: CodeEditorSlashTrigger) => void;
|
|
226
|
+
/**
|
|
227
|
+
* Actions shown in a floating toolbar when the user selects non-empty text.
|
|
228
|
+
*/
|
|
229
|
+
selectionActions?: CodeEditorSelectionAction[];
|
|
175
230
|
/**
|
|
176
231
|
* When true, shows inline syntax-error squiggles for supported languages.
|
|
177
232
|
* Defaults to true.
|
|
@@ -216,5 +271,5 @@ export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
216
271
|
* Styling relies on host CSS variables (`--mac-*`, `--font-mono`) and the `.app-no-drag`
|
|
217
272
|
* class defined in HarborClient `styles.css`.
|
|
218
273
|
*/
|
|
219
|
-
export declare function CodeEditor({ value, onChange, language, readOnly, editable, placeholder, placeholderHighlight, minHeight, height, onHeightChange, initialScrollTop, initialSelection, onViewStateChange, className, variables, onEditVariable, completionSource, slashCommands, onSlashCommand, lint, themeOverride, setupOverride, fontSize, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...props }: Props): JSX.Element;
|
|
274
|
+
export declare function CodeEditor({ value, onChange, language, readOnly, editable, placeholder, placeholderHighlight, minHeight, height, onHeightChange, initialScrollTop, initialSelection, onViewStateChange, className, variables, onEditVariable, completionSource, slashCommands, onSlashCommand, selectionActions, lint, themeOverride, setupOverride, fontSize, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...props }: Props): JSX.Element;
|
|
220
275
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CodeEditor/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAmC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CodeEditor/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -11,8 +11,10 @@ import CodeMirrorImport from '@uiw/react-codemirror';
|
|
|
11
11
|
import { normalizeCodeEditorFontSize } from '../../ui/codeEditorSettings.js';
|
|
12
12
|
import { VARIABLE_NAME_CHARS, getVariableTooltipContent } from '../../variables/index.js';
|
|
13
13
|
import { Button } from '../Button/index.js';
|
|
14
|
+
import { FaIcon } from '../FaIcon/index.js';
|
|
14
15
|
import { buildVariableTooltipDom } from '../VariableTooltip/dom.js';
|
|
15
16
|
import { VariableTooltipValue } from '../VariableTooltip/index.js';
|
|
17
|
+
import { portalToBody } from '../portalToBody.js';
|
|
16
18
|
import { useCodeEditorConfig } from './config.js';
|
|
17
19
|
import { createBuiltInSyntaxHighlighting, createEditorTheme } from './editorChrome.js';
|
|
18
20
|
import { createSlashCommandHighlighter } from './slashCommandHighlighter.js';
|
|
@@ -34,6 +36,10 @@ function clampSelection(docLength, selection) {
|
|
|
34
36
|
}
|
|
35
37
|
/** Debounce interval for {@link Props.onViewStateChange} notifications. */
|
|
36
38
|
const VIEW_STATE_DEBOUNCE_MS = 300;
|
|
39
|
+
/** Delay before showing the selection action toolbar after selection settles. */
|
|
40
|
+
const SELECTION_TOOLBAR_SHOW_DELAY_MS = 450;
|
|
41
|
+
/** Extra viewport gap between the selection top edge and the portaled toolbar. */
|
|
42
|
+
const SELECTION_TOOLBAR_OFFSET_PX = 16;
|
|
37
43
|
const variableMatcher = new MatchDecorator({
|
|
38
44
|
regexp: new RegExp(`\\{\\{\\s*([${VARIABLE_NAME_CHARS}]+)\\s*\\}\\}`, 'g'),
|
|
39
45
|
decoration: Decoration.mark({ class: 'cm-variable-token' })
|
|
@@ -250,6 +256,210 @@ function variableTooltipEscapeHandler(isOpen, onDismiss, getValidationDescribedB
|
|
|
250
256
|
}
|
|
251
257
|
});
|
|
252
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Computes viewport anchor coordinates for the selection action toolbar.
|
|
261
|
+
*
|
|
262
|
+
* @param view - CodeMirror editor view.
|
|
263
|
+
* @param selectionFrom - Start offset (inclusive) of the selection.
|
|
264
|
+
* @param selectionTo - End offset (exclusive) of the selection.
|
|
265
|
+
* @returns Toolbar anchor position, or null when coords are unavailable.
|
|
266
|
+
*/
|
|
267
|
+
function computeSelectionActionToolbarCoords(view, selectionFrom, selectionTo) {
|
|
268
|
+
const startCoords = view.coordsAtPos(selectionFrom);
|
|
269
|
+
if (!startCoords) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
const endCoords = view.coordsAtPos(selectionTo);
|
|
273
|
+
const startCenter = startCoords.left + (startCoords.right - startCoords.left) / 2;
|
|
274
|
+
const endCenter = endCoords
|
|
275
|
+
? endCoords.left + (endCoords.right - endCoords.left) / 2
|
|
276
|
+
: startCenter;
|
|
277
|
+
return {
|
|
278
|
+
top: startCoords.top,
|
|
279
|
+
left: (startCenter + endCenter) / 2
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Builds update and pointer handlers that debounce toolbar display until selection settles.
|
|
284
|
+
*/
|
|
285
|
+
function createSelectionActionToolbarExtensions(onToolbarChange, isEnabled, isOpen, onDismiss) {
|
|
286
|
+
const controller = {
|
|
287
|
+
showTimer: undefined,
|
|
288
|
+
isPointerSelecting: false,
|
|
289
|
+
isToolbarOpen: false,
|
|
290
|
+
pendingState: null
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Clears a scheduled toolbar reveal without changing open state.
|
|
294
|
+
*/
|
|
295
|
+
const clearShowTimer = () => {
|
|
296
|
+
if (controller.showTimer) {
|
|
297
|
+
clearTimeout(controller.showTimer);
|
|
298
|
+
controller.showTimer = undefined;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* Notifies React of toolbar visibility while keeping controller state in sync.
|
|
303
|
+
*/
|
|
304
|
+
const notifyToolbarChange = (state) => {
|
|
305
|
+
controller.isToolbarOpen = state != null;
|
|
306
|
+
if (state == null) {
|
|
307
|
+
controller.pendingState = null;
|
|
308
|
+
}
|
|
309
|
+
onToolbarChange(state);
|
|
310
|
+
};
|
|
311
|
+
/**
|
|
312
|
+
* Hides the toolbar immediately and cancels any pending reveal.
|
|
313
|
+
*/
|
|
314
|
+
const dismissToolbar = () => {
|
|
315
|
+
clearShowTimer();
|
|
316
|
+
if (controller.isToolbarOpen || controller.pendingState != null) {
|
|
317
|
+
notifyToolbarChange(null);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* Schedules toolbar display after the configured settle delay.
|
|
322
|
+
*/
|
|
323
|
+
const scheduleShow = (state) => {
|
|
324
|
+
controller.pendingState = state;
|
|
325
|
+
clearShowTimer();
|
|
326
|
+
if (controller.isPointerSelecting) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
controller.showTimer = setTimeout(() => {
|
|
330
|
+
controller.showTimer = undefined;
|
|
331
|
+
if (controller.isPointerSelecting) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
notifyToolbarChange(state);
|
|
335
|
+
}, SELECTION_TOOLBAR_SHOW_DELAY_MS);
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* Repositions or reveals the toolbar without waiting when it is already open.
|
|
339
|
+
*/
|
|
340
|
+
const showImmediately = (state) => {
|
|
341
|
+
clearShowTimer();
|
|
342
|
+
notifyToolbarChange(state);
|
|
343
|
+
};
|
|
344
|
+
const updateListener = EditorView.updateListener.of((update) => {
|
|
345
|
+
if (!isEnabled()) {
|
|
346
|
+
dismissToolbar();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (!update.selectionSet && !update.docChanged && !update.viewportChanged) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const { from, to } = update.state.selection.main;
|
|
353
|
+
if (from === to) {
|
|
354
|
+
dismissToolbar();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const selectionFrom = Math.min(from, to);
|
|
358
|
+
const selectionTo = Math.max(from, to);
|
|
359
|
+
const text = update.state.sliceDoc(selectionFrom, selectionTo);
|
|
360
|
+
if (!text.trim()) {
|
|
361
|
+
dismissToolbar();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const coords = computeSelectionActionToolbarCoords(update.view, selectionFrom, selectionTo);
|
|
365
|
+
if (!coords) {
|
|
366
|
+
dismissToolbar();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const nextState = {
|
|
370
|
+
top: coords.top,
|
|
371
|
+
left: coords.left,
|
|
372
|
+
text,
|
|
373
|
+
from: selectionFrom,
|
|
374
|
+
to: selectionTo
|
|
375
|
+
};
|
|
376
|
+
if (isOpen() && !update.selectionSet && update.viewportChanged) {
|
|
377
|
+
showImmediately(nextState);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (isOpen() && update.selectionSet) {
|
|
381
|
+
scheduleShow(nextState);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
scheduleShow(nextState);
|
|
385
|
+
});
|
|
386
|
+
const pointerGuard = EditorView.domEventHandlers({
|
|
387
|
+
/**
|
|
388
|
+
* Suppresses toolbar reveal while the user is drag-selecting with the primary button.
|
|
389
|
+
*/
|
|
390
|
+
pointerdown(event) {
|
|
391
|
+
if (event.button === 0) {
|
|
392
|
+
controller.isPointerSelecting = true;
|
|
393
|
+
clearShowTimer();
|
|
394
|
+
}
|
|
395
|
+
return false;
|
|
396
|
+
},
|
|
397
|
+
/**
|
|
398
|
+
* Resumes debounced reveal after drag-select completes.
|
|
399
|
+
*/
|
|
400
|
+
pointerup() {
|
|
401
|
+
controller.isPointerSelecting = false;
|
|
402
|
+
if (controller.pendingState != null && !isOpen()) {
|
|
403
|
+
scheduleShow(controller.pendingState);
|
|
404
|
+
}
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
const dismissHandler = EditorView.domEventHandlers({
|
|
409
|
+
keydown(event) {
|
|
410
|
+
if (event.key === 'Escape' && isOpen()) {
|
|
411
|
+
event.preventDefault();
|
|
412
|
+
dismissToolbar();
|
|
413
|
+
onDismiss();
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
const cleanupPlugin = ViewPlugin.fromClass(class {
|
|
420
|
+
/**
|
|
421
|
+
* Clears any pending toolbar reveal when the editor extension is destroyed.
|
|
422
|
+
*/
|
|
423
|
+
destroy() {
|
|
424
|
+
clearShowTimer();
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
return [updateListener, pointerGuard, dismissHandler, cleanupPlugin];
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Registers keyboard shortcuts for selection toolbar actions.
|
|
431
|
+
*
|
|
432
|
+
* @param actions - Selection actions that define a {@link CodeEditorSelectionAction.key}.
|
|
433
|
+
* @param onToolbarChange - Clears the floating toolbar after a shortcut fires.
|
|
434
|
+
*/
|
|
435
|
+
function createSelectionActionKeymap(actions, onToolbarChange) {
|
|
436
|
+
const keyedActions = actions.filter((action) => action.key);
|
|
437
|
+
if (keyedActions.length === 0) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
return Prec.highest(keymap.of(keyedActions.map((action) => ({
|
|
441
|
+
key: action.key,
|
|
442
|
+
run(view) {
|
|
443
|
+
const { from, to } = view.state.selection.main;
|
|
444
|
+
if (from === to) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
const selectionFrom = Math.min(from, to);
|
|
448
|
+
const selectionTo = Math.max(from, to);
|
|
449
|
+
const text = view.state.sliceDoc(selectionFrom, selectionTo);
|
|
450
|
+
if (!text.trim()) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
action.onSelect({
|
|
454
|
+
text,
|
|
455
|
+
from: selectionFrom,
|
|
456
|
+
to: selectionTo
|
|
457
|
+
});
|
|
458
|
+
onToolbarChange(null);
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
}))));
|
|
462
|
+
}
|
|
253
463
|
/**
|
|
254
464
|
* Builds a hover tooltip extension for {{variable}} tokens.
|
|
255
465
|
*/
|
|
@@ -309,6 +519,13 @@ function buildCoreExtensions(options) {
|
|
|
309
519
|
if (options.hasVariables) {
|
|
310
520
|
next.push(variableHighlighter, variableTooltip(options.getVariables, options.getOnEditVariable), variableSelectionTooltip(options.tooltipId, options.onSelectionTooltipChange, options.getValidationDescribedBy), variableTooltipEscapeHandler(options.isSelectionTooltipOpen, options.onDismissSelectionTooltip, options.getValidationDescribedBy));
|
|
311
521
|
}
|
|
522
|
+
if (options.hasSelectionActions) {
|
|
523
|
+
next.push(...createSelectionActionToolbarExtensions(options.onSelectionActionToolbarChange, () => options.hasSelectionActions, options.isSelectionActionToolbarOpen, options.onDismissSelectionActionToolbar));
|
|
524
|
+
const keymapExtension = createSelectionActionKeymap(options.selectionActions, options.onSelectionActionToolbarChange);
|
|
525
|
+
if (keymapExtension) {
|
|
526
|
+
next.push(keymapExtension);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
312
529
|
return next;
|
|
313
530
|
}
|
|
314
531
|
/**
|
|
@@ -396,7 +613,7 @@ function buildPlaceholderExtensions(options) {
|
|
|
396
613
|
* Styling relies on host CSS variables (`--mac-*`, `--font-mono`) and the `.app-no-drag`
|
|
397
614
|
* class defined in HarborClient `styles.css`.
|
|
398
615
|
*/
|
|
399
|
-
export function CodeEditor({ value, onChange, language = 'text', readOnly = false, editable, placeholder, placeholderHighlight = false, minHeight = '144px', height, onHeightChange, initialScrollTop, initialSelection, onViewStateChange, className = '', variables, onEditVariable, completionSource, slashCommands, onSlashCommand, lint = true, themeOverride, setupOverride, fontSize, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...props }) {
|
|
616
|
+
export function CodeEditor({ value, onChange, language = 'text', readOnly = false, editable, placeholder, placeholderHighlight = false, minHeight = '144px', height, onHeightChange, initialScrollTop, initialSelection, onViewStateChange, className = '', variables, onEditVariable, completionSource, slashCommands, onSlashCommand, selectionActions, lint = true, themeOverride, setupOverride, fontSize, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...props }) {
|
|
400
617
|
const config = useCodeEditorConfig();
|
|
401
618
|
const resolvedTheme = themeOverride ?? config.theme;
|
|
402
619
|
const resolvedSetup = setupOverride ?? (readOnly ? null : config.setup);
|
|
@@ -408,6 +625,15 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
408
625
|
selectionTooltipRef.current = selectionTooltip;
|
|
409
626
|
const setSelectionTooltipRef = useRef(setSelectionTooltip);
|
|
410
627
|
setSelectionTooltipRef.current = setSelectionTooltip;
|
|
628
|
+
const [selectionActionToolbar, setSelectionActionToolbar] = useState(null);
|
|
629
|
+
const selectionActionToolbarRef = useRef(selectionActionToolbar);
|
|
630
|
+
selectionActionToolbarRef.current = selectionActionToolbar;
|
|
631
|
+
const setSelectionActionToolbarRef = useRef(setSelectionActionToolbar);
|
|
632
|
+
setSelectionActionToolbarRef.current = setSelectionActionToolbar;
|
|
633
|
+
const selectionToolbarElementRef = useRef(null);
|
|
634
|
+
const selectionActionsRef = useRef(selectionActions);
|
|
635
|
+
selectionActionsRef.current = selectionActions;
|
|
636
|
+
const hasSelectionActions = selectionActions != null && selectionActions.length > 0;
|
|
411
637
|
const ariaDescribedByRef = useRef(ariaDescribedBy);
|
|
412
638
|
ariaDescribedByRef.current = ariaDescribedBy;
|
|
413
639
|
const onSlashCommandRef = useRef(onSlashCommand);
|
|
@@ -497,6 +723,33 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
497
723
|
editorViewRef.current = null;
|
|
498
724
|
};
|
|
499
725
|
}, [flushViewState]);
|
|
726
|
+
/**
|
|
727
|
+
* Dismisses the portaled selection toolbar when the user clicks outside the editor and toolbar.
|
|
728
|
+
*/
|
|
729
|
+
useEffect(() => {
|
|
730
|
+
if (!selectionActionToolbar) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Closes the toolbar on outside pointer interaction without racing editor blur during selection.
|
|
735
|
+
*/
|
|
736
|
+
const handlePointerDown = (event) => {
|
|
737
|
+
const target = event.target;
|
|
738
|
+
if (!(target instanceof Node)) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const editorRoot = editorViewRef.current?.dom;
|
|
742
|
+
const toolbar = selectionToolbarElementRef.current;
|
|
743
|
+
if (editorRoot?.contains(target) || toolbar?.contains(target)) {
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
setSelectionActionToolbar(null);
|
|
747
|
+
};
|
|
748
|
+
document.addEventListener('pointerdown', handlePointerDown, true);
|
|
749
|
+
return () => {
|
|
750
|
+
document.removeEventListener('pointerdown', handlePointerDown, true);
|
|
751
|
+
};
|
|
752
|
+
}, [selectionActionToolbar]);
|
|
500
753
|
/**
|
|
501
754
|
* Persists wrapper height only after the user finishes a native resize-y drag on the grip.
|
|
502
755
|
* Ignores mount and layout settling so height props do not reconfigure CodeMirror in a loop.
|
|
@@ -613,6 +866,15 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
613
866
|
isSelectionTooltipOpen: () => selectionTooltipRef.current != null,
|
|
614
867
|
onDismissSelectionTooltip: () => {
|
|
615
868
|
setSelectionTooltipRef.current(null);
|
|
869
|
+
},
|
|
870
|
+
hasSelectionActions,
|
|
871
|
+
selectionActions: selectionActions ?? [],
|
|
872
|
+
onSelectionActionToolbarChange: (state) => {
|
|
873
|
+
setSelectionActionToolbarRef.current(state);
|
|
874
|
+
},
|
|
875
|
+
isSelectionActionToolbarOpen: () => selectionActionToolbarRef.current != null,
|
|
876
|
+
onDismissSelectionActionToolbar: () => {
|
|
877
|
+
setSelectionActionToolbarRef.current(null);
|
|
616
878
|
}
|
|
617
879
|
}), [
|
|
618
880
|
editorThemeExt,
|
|
@@ -623,6 +885,8 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
623
885
|
language,
|
|
624
886
|
lint,
|
|
625
887
|
hasVariables,
|
|
888
|
+
hasSelectionActions,
|
|
889
|
+
selectionActions,
|
|
626
890
|
tooltipId,
|
|
627
891
|
getVariables,
|
|
628
892
|
getOnEditVariable
|
|
@@ -821,6 +1085,20 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
821
1085
|
? getVariableTooltipContent(selectionTooltip.key, variables ?? [])
|
|
822
1086
|
: null;
|
|
823
1087
|
const wrapperStyle = height ? { height } : undefined;
|
|
1088
|
+
const activeSelectionActions = selectionActionsRef.current ?? [];
|
|
1089
|
+
const selectionActionToolbarNode = selectionActionToolbar && hasSelectionActions ? (_jsx("div", { ref: selectionToolbarElementRef, role: "toolbar", "aria-label": "Selection actions", className: "hc-code-editor-selection-toolbar app-no-drag pointer-events-auto fixed z-50 flex -translate-x-1/2 -translate-y-full items-center gap-1 bg-transparent p-0 text-[14px] text-text", style: {
|
|
1090
|
+
top: selectionActionToolbar.top - SELECTION_TOOLBAR_OFFSET_PX,
|
|
1091
|
+
left: selectionActionToolbar.left
|
|
1092
|
+
}, children: activeSelectionActions.map((action) => (_jsxs("button", { type: "button", className: "hc-code-editor-selection-action inline-flex cursor-pointer items-center gap-1.5 rounded-md border border-separator bg-control px-2 py-1 text-[14px] text-text shadow-sm hover:bg-surface focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent", "aria-label": action.ariaLabel, onMouseDown: (event) => {
|
|
1093
|
+
event.preventDefault();
|
|
1094
|
+
}, onClick: () => {
|
|
1095
|
+
action.onSelect({
|
|
1096
|
+
text: selectionActionToolbar.text,
|
|
1097
|
+
from: selectionActionToolbar.from,
|
|
1098
|
+
to: selectionActionToolbar.to
|
|
1099
|
+
});
|
|
1100
|
+
setSelectionActionToolbar(null);
|
|
1101
|
+
}, children: [action.icon ? _jsx(FaIcon, { icon: action.icon, className: "h-3.5 w-3.5" }) : null, _jsx("span", { children: action.label }), action.shortcutHint ? (_jsx("span", { className: "text-[14px] text-muted", children: action.shortcutHint })) : null] }, action.id))) })) : null;
|
|
824
1102
|
return (_jsxs("div", { ref: wrapperRef, ...props, className: wrapperClassName, style: wrapperStyle, children: [createElement(CodeMirrorImport, {
|
|
825
1103
|
value,
|
|
826
1104
|
onChange: readOnly ? undefined : stableOnChange,
|
|
@@ -837,5 +1115,5 @@ export function CodeEditor({ value, onChange, language = 'text', readOnly = fals
|
|
|
837
1115
|
event.preventDefault();
|
|
838
1116
|
onEditVariable(selectionTooltip.key);
|
|
839
1117
|
setSelectionTooltip(null);
|
|
840
|
-
}, children: "Edit value" })) : null] })) : null] }));
|
|
1118
|
+
}, children: "Edit value" })) : null] })) : null, selectionActionToolbarNode ? portalToBody(selectionActionToolbarNode) : null] }));
|
|
841
1119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Toolbar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjG;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAE/C;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CACjD;AAED,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACtF;;OAEG;IACH,OAAO,EAAE,aAAa,EAAE,CAAC;IAEzB;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAE1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Toolbar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjG;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAE/C;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CACjD;AAED,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACtF;;OAEG;IACH,OAAO,EAAE,aAAa,EAAE,CAAC;IAEzB;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAE1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsDD;;GAEG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,OAAO,EACP,SAAqB,EACrB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAqBrB"}
|
|
@@ -3,8 +3,15 @@ import { FaIcon } from '../FaIcon/index.js';
|
|
|
3
3
|
import { cn } from '../utils.js';
|
|
4
4
|
/**
|
|
5
5
|
* Tailwind classes for toolbar icon action buttons.
|
|
6
|
+
*
|
|
7
|
+
* @param pressed - Whether the action is in a pressed/toggled-on state.
|
|
8
|
+
* @returns Class string for the action button.
|
|
6
9
|
*/
|
|
7
|
-
|
|
10
|
+
function toolbarActionButtonClasses(pressed) {
|
|
11
|
+
return cn('hc-toolbar-action app-no-drag inline-flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border-none text-text', pressed
|
|
12
|
+
? 'bg-selection'
|
|
13
|
+
: 'bg-transparent hover:bg-selection focus-visible:bg-selection focus-visible:text-text', 'disabled:cursor-not-allowed disabled:opacity-50');
|
|
14
|
+
}
|
|
8
15
|
/**
|
|
9
16
|
* Renders a single toolbar icon action with optional popover content.
|
|
10
17
|
*
|
|
@@ -13,7 +20,7 @@ const TOOLBAR_ACTION_BUTTON = 'hc-toolbar-action inline-flex h-7 w-7 shrink-0 cu
|
|
|
13
20
|
*/
|
|
14
21
|
function renderAction(action) {
|
|
15
22
|
const title = action.title ?? action.label;
|
|
16
|
-
return (_jsxs("div", { className: "hc-toolbar-action-wrap relative", children: [_jsx("button", { type: "button", ref: action.buttonRef, className:
|
|
23
|
+
return (_jsxs("div", { className: "hc-toolbar-action-wrap relative", children: [_jsx("button", { type: "button", ref: action.buttonRef, className: toolbarActionButtonClasses(action.ariaPressed === true), title: title, "aria-label": action.label, "aria-expanded": action.ariaExpanded, "aria-pressed": action.ariaPressed, "aria-haspopup": action.ariaHaspopup, disabled: action.disabled, onClick: action.onClick, children: _jsx(FaIcon, { icon: action.icon, className: cn('hc-toolbar-action-icon h-5! w-5!', action.ariaPressed === true ? 'opacity-100' : 'opacity-50') }) }), action.popover] }, action.id));
|
|
17
24
|
}
|
|
18
25
|
/**
|
|
19
26
|
* Top-of-sidebar toolbar with left-aligned actions and optional right-aligned toggles.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/VariableInput/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,aAAa,EAAc,MAAM,OAAO,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/VariableInput/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,aAAa,EAAc,MAAM,OAAO,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAqBnE,MAAM,WAAW,KAAM,SAAQ,IAAI,CACjC,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,GAAG,WAAW,GAAG,IAAI,GAAG,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAC9F;IACC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAEzD;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,WAAW,EACX,SAAS,EACT,SAAc,EACd,gBAAgB,EAChB,cAAc,EACd,EAAE,EACF,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,MAAM,EACN,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgVrB"}
|
|
@@ -7,6 +7,10 @@ import { Button } from '../Button/index.js';
|
|
|
7
7
|
import { VariableTooltipValue } from '../VariableTooltip/index.js';
|
|
8
8
|
import { Input } from '../forms/index.js';
|
|
9
9
|
import { cn } from '../utils.js';
|
|
10
|
+
/** Delay after the pointer stops moving before a hover tooltip is shown. */
|
|
11
|
+
const TOOLTIP_SHOW_DELAY_MS = 500;
|
|
12
|
+
/** Grace period before hiding so the pointer can reach the tooltip. */
|
|
13
|
+
const TOOLTIP_HIDE_DELAY_MS = 400;
|
|
10
14
|
/**
|
|
11
15
|
* Text input that highlights {{variable}} tokens and shows resolved values on hover.
|
|
12
16
|
*
|
|
@@ -19,6 +23,7 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
19
23
|
const backdropRef = useRef(null);
|
|
20
24
|
const spanRefs = useRef(new Map());
|
|
21
25
|
const hideTimer = useRef(null);
|
|
26
|
+
const showTimer = useRef(null);
|
|
22
27
|
const [tooltip, setTooltip] = useState(null);
|
|
23
28
|
const tooltipId = useId();
|
|
24
29
|
const { open: autocompleteOpen, items: autocompleteItems, activeIndex: autocompleteActiveIndex, listboxId, onFocus: openAutocomplete, onBlur: closeAutocomplete, onInputKeyDown, selectItem, setActiveIndex, closeSuggestions } = useAutocomplete({
|
|
@@ -45,20 +50,15 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
45
50
|
*/
|
|
46
51
|
const scheduleHide = () => {
|
|
47
52
|
cancelHide();
|
|
48
|
-
hideTimer.current = window.setTimeout(() => setTooltip(null),
|
|
53
|
+
hideTimer.current = window.setTimeout(() => setTooltip(null), TOOLTIP_HIDE_DELAY_MS);
|
|
49
54
|
};
|
|
50
55
|
/**
|
|
51
|
-
* Clears any pending tooltip
|
|
56
|
+
* Clears any pending tooltip show timer.
|
|
52
57
|
*/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const syncScroll = () => {
|
|
58
|
-
const input = inputRef.current;
|
|
59
|
-
const backdrop = backdropRef.current;
|
|
60
|
-
if (input && backdrop) {
|
|
61
|
-
backdrop.scrollLeft = input.scrollLeft;
|
|
58
|
+
const cancelShow = () => {
|
|
59
|
+
if (showTimer.current != null) {
|
|
60
|
+
window.clearTimeout(showTimer.current);
|
|
61
|
+
showTimer.current = null;
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
/**
|
|
@@ -73,6 +73,37 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
73
73
|
left
|
|
74
74
|
});
|
|
75
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Shows the tooltip once the pointer has stopped moving for {@link TOOLTIP_SHOW_DELAY_MS}.
|
|
78
|
+
*
|
|
79
|
+
* @param key - Variable name from the hovered {{key}} token.
|
|
80
|
+
* @param top - Screen Y coordinate for tooltip placement.
|
|
81
|
+
* @param left - Screen X coordinate for tooltip placement.
|
|
82
|
+
*/
|
|
83
|
+
const scheduleShow = (key, top, left) => {
|
|
84
|
+
cancelShow();
|
|
85
|
+
showTimer.current = window.setTimeout(() => {
|
|
86
|
+
showTimer.current = null;
|
|
87
|
+
showTooltipForKey(key, top, left);
|
|
88
|
+
}, TOOLTIP_SHOW_DELAY_MS);
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Clears pending tooltip timers when the component unmounts.
|
|
92
|
+
*/
|
|
93
|
+
useEffect(() => () => {
|
|
94
|
+
cancelHide();
|
|
95
|
+
cancelShow();
|
|
96
|
+
}, []);
|
|
97
|
+
/**
|
|
98
|
+
* Keeps the colored backdrop aligned with horizontal scroll in the input.
|
|
99
|
+
*/
|
|
100
|
+
const syncScroll = () => {
|
|
101
|
+
const input = inputRef.current;
|
|
102
|
+
const backdrop = backdropRef.current;
|
|
103
|
+
if (input && backdrop) {
|
|
104
|
+
backdrop.scrollLeft = input.scrollLeft;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
76
107
|
/**
|
|
77
108
|
* Updates the tooltip based on the current text caret position.
|
|
78
109
|
*/
|
|
@@ -105,7 +136,7 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
105
136
|
showTooltipForKey(match.key, rect.top, rect.left + rect.width / 2);
|
|
106
137
|
};
|
|
107
138
|
/**
|
|
108
|
-
* Shows a tooltip when the pointer
|
|
139
|
+
* Shows a tooltip when the pointer rests over a variable token span.
|
|
109
140
|
*/
|
|
110
141
|
const handleMouseMove = (e) => {
|
|
111
142
|
cancelHide();
|
|
@@ -120,10 +151,18 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
120
151
|
e.clientX <= rect.right &&
|
|
121
152
|
e.clientY >= rect.top &&
|
|
122
153
|
e.clientY <= rect.bottom) {
|
|
123
|
-
|
|
154
|
+
scheduleShow(token.key, rect.top, rect.left + rect.width / 2);
|
|
124
155
|
return;
|
|
125
156
|
}
|
|
126
157
|
}
|
|
158
|
+
cancelShow();
|
|
159
|
+
scheduleHide();
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Cancels a pending show and hides the tooltip when the pointer leaves the input.
|
|
163
|
+
*/
|
|
164
|
+
const handleMouseLeave = () => {
|
|
165
|
+
cancelShow();
|
|
127
166
|
scheduleHide();
|
|
128
167
|
};
|
|
129
168
|
/**
|
|
@@ -167,7 +206,7 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
167
206
|
}, onFocus: () => {
|
|
168
207
|
openAutocomplete();
|
|
169
208
|
updateTooltipFromCaret();
|
|
170
|
-
}, onBlur: closeAutocomplete, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onSelect: updateTooltipFromCaret, onClick: updateTooltipFromCaret, onScroll: syncScroll, onMouseMove: handleMouseMove, onMouseLeave:
|
|
209
|
+
}, onBlur: closeAutocomplete, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onSelect: updateTooltipFromCaret, onClick: updateTooltipFromCaret, onScroll: syncScroll, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave }), source && (_jsx(SuggestionList, { open: autocompleteOpen, items: autocompleteItems, activeIndex: autocompleteActiveIndex, anchorRef: inputRef, listboxId: listboxId, onSelect: selectItem, onActiveIndexChange: setActiveIndex, onClose: closeSuggestions })), tooltip && tooltipContent && (_jsxs("div", { id: tooltipId, role: "tooltip", className: "hc-variable-input-tooltip pointer-events-auto fixed z-50 flex max-w-sm -translate-x-1/2 -translate-y-full flex-col gap-2 rounded-lg border border-separator bg-surface px-4 py-3 text-[16px] text-text shadow-md after:pointer-events-auto after:absolute after:right-0 after:-bottom-2 after:left-0 after:h-2 after:content-['']", style: { top: tooltip.top - 4, left: tooltip.left }, onMouseEnter: cancelHide, onMouseLeave: scheduleHide, children: [_jsx(VariableTooltipValue, { value: tooltipContent.text, variableKey: tooltip.key, muted: tooltipContent.muted }), onEditVariable && (_jsx(Button, { variant: "secondary", className: "hc-variable-input-tooltip-edit self-start", "aria-label": `Edit value for ${tooltip.key}`, onClick: () => {
|
|
171
210
|
onEditVariable(tooltip.key);
|
|
172
211
|
setTooltip(null);
|
|
173
212
|
}, children: "Edit value" }))] }))] }));
|
|
@@ -10,7 +10,7 @@ export { Button } from './Button/index.js';
|
|
|
10
10
|
export { CodeEditor, CODE_EDITOR_THEME_OPTIONS } from './CodeEditor/index.js';
|
|
11
11
|
export { CodeEditorConfigProvider, useCodeEditorConfig, DEFAULT_CODE_EDITOR_CONFIG } from './CodeEditor/config.js';
|
|
12
12
|
export type { CodeEditorConfig } from './CodeEditor/config.js';
|
|
13
|
-
export type { Props as CodeEditorProps, CodeEditorLanguage, CodeEditorSelectionRange, CodeEditorSlashCommand, CodeEditorSlashCoords, CodeEditorSlashTrigger, CodeEditorViewState } from './CodeEditor/index.js';
|
|
13
|
+
export type { Props as CodeEditorProps, CodeEditorLanguage, CodeEditorSelectionAction, CodeEditorSelectionRange, CodeEditorSlashCommand, CodeEditorSlashCoords, CodeEditorSlashTrigger, CodeEditorTextSelection, CodeEditorViewState } from './CodeEditor/index.js';
|
|
14
14
|
export { EmptyState } from './EmptyState/index.js';
|
|
15
15
|
export { FaIcon } from './FaIcon/index.js';
|
|
16
16
|
export { FieldError } from './FieldError/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|