@uipath/apollo-wind 2.79.2 → 2.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/components/ui/editable-text.cjs +251 -0
  2. package/dist/components/ui/editable-text.d.ts +48 -0
  3. package/dist/components/ui/editable-text.js +217 -0
  4. package/dist/components/ui/field-addons/field-menu.cjs +2 -1
  5. package/dist/components/ui/field-addons/field-menu.d.ts +6 -1
  6. package/dist/components/ui/field-addons/field-menu.js +2 -1
  7. package/dist/components/ui/field-addons/value-mode-switch-dialog.cjs +2 -1
  8. package/dist/components/ui/field-addons/value-mode-switch-dialog.d.ts +6 -1
  9. package/dist/components/ui/field-addons/value-mode-switch-dialog.js +2 -1
  10. package/dist/components/ui/index.cjs +214 -201
  11. package/dist/components/ui/index.d.ts +1 -0
  12. package/dist/components/ui/index.js +1 -0
  13. package/dist/components/ui/input-group.cjs +7 -3
  14. package/dist/components/ui/input-group.d.ts +1 -1
  15. package/dist/components/ui/input-group.js +7 -3
  16. package/dist/components/ui/quick-form-field/components/field-header.cjs +41 -38
  17. package/dist/components/ui/quick-form-field/components/field-header.d.ts +13 -4
  18. package/dist/components/ui/quick-form-field/components/field-header.js +38 -38
  19. package/dist/components/ui/quick-form-field/index.d.ts +1 -1
  20. package/dist/components/ui/quick-form-field/quick-form-field.cjs +134 -17
  21. package/dist/components/ui/quick-form-field/quick-form-field.d.ts +6 -3
  22. package/dist/components/ui/quick-form-field/quick-form-field.js +136 -19
  23. package/dist/components/ui/quick-form-field/types.cjs +8 -0
  24. package/dist/components/ui/quick-form-field/types.d.ts +81 -14
  25. package/dist/components/ui/quick-form-field/types.js +8 -0
  26. package/dist/components/ui/quick-form-field/utils.cjs +30 -1
  27. package/dist/components/ui/quick-form-field/utils.d.ts +8 -0
  28. package/dist/components/ui/quick-form-field/utils.js +27 -1
  29. package/dist/components/ui/variable-value-control.cjs +7 -4
  30. package/dist/components/ui/variable-value-control.d.ts +5 -1
  31. package/dist/components/ui/variable-value-control.js +7 -4
  32. package/dist/index.cjs +4 -0
  33. package/dist/index.d.ts +3 -1
  34. package/dist/index.js +2 -1
  35. package/dist/styles.css +69 -9
  36. package/package.json +1 -1
@@ -31,20 +31,29 @@ const external_lucide_react_namespaceObject = require("lucide-react");
31
31
  const external_react_namespaceObject = require("react");
32
32
  const external_calendar_cjs_namespaceObject = require("../calendar.cjs");
33
33
  const external_datetime_picker_cjs_namespaceObject = require("../datetime-picker.cjs");
34
+ const external_editable_text_cjs_namespaceObject = require("../editable-text.cjs");
34
35
  const external_file_upload_cjs_namespaceObject = require("../file-upload.cjs");
35
36
  const external_input_group_cjs_namespaceObject = require("../input-group.cjs");
37
+ const external_label_cjs_namespaceObject = require("../label.cjs");
36
38
  const external_multi_select_cjs_namespaceObject = require("../multi-select.cjs");
37
39
  const external_popover_cjs_namespaceObject = require("../popover.cjs");
40
+ const external_prompt_value_control_cjs_namespaceObject = require("../prompt-value-control.cjs");
38
41
  const external_select_cjs_namespaceObject = require("../select.cjs");
39
42
  const external_switch_cjs_namespaceObject = require("../switch.cjs");
43
+ const external_variable_value_control_cjs_namespaceObject = require("../variable-value-control.cjs");
40
44
  const index_cjs_namespaceObject = require("../../../lib/index.cjs");
41
45
  const date_value_cjs_namespaceObject = require("../../../lib/date-value.cjs");
42
46
  const field_menu_cjs_namespaceObject = require("../field-addons/field-menu.cjs");
47
+ const value_mode_switch_dialog_cjs_namespaceObject = require("../field-addons/value-mode-switch-dialog.cjs");
43
48
  const field_header_cjs_namespaceObject = require("./components/field-header.cjs");
44
49
  const lock_toggle_button_cjs_namespaceObject = require("./components/lock-toggle-button.cjs");
45
50
  const external_types_cjs_namespaceObject = require("./types.cjs");
46
51
  const external_utils_cjs_namespaceObject = require("./utils.cjs");
47
- function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, showLock = true, disabled = false, leadingAddon, trailingAddon, more, mode = 'literal', onModeChange, renderExpressionEditor, renderModeControl, fieldType = 'string', fieldTypes, onFieldTypeChange, required, onRequiredChange, label, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions = true, options = external_utils_cjs_namespaceObject.DEFAULT_SELECT_OPTIONS, onGenerateWithAi, onInsertVariable, variables = [], id, className }) {
52
+ const DEFAULT_VALUE_MODES = [
53
+ 'literal',
54
+ 'expression'
55
+ ];
56
+ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, showLock = true, disabled = false, leadingAddon, trailingAddon, more, mode = 'literal', onModeChange, valueModes = DEFAULT_VALUE_MODES, confirmModeChange, renderExpressionEditor, renderModeControl, fieldType = 'string', fieldTypes, onFieldTypeChange, required, onRequiredChange, label, onLabelChange, isEditingLabel, onIsEditingLabelChange, labelAddon, tooltip, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions = true, options = external_utils_cjs_namespaceObject.DEFAULT_SELECT_OPTIONS, onGenerateWithAi, onInsertVariable, variables = [], id, className }) {
48
57
  const strings = (0, external_react_namespaceObject.useMemo)(()=>({
49
58
  ...external_types_cjs_namespaceObject.DEFAULT_QUICK_FORM_FIELD_STRINGS,
50
59
  ...stringOverrides
@@ -55,8 +64,17 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
55
64
  const valueInputRef = (0, external_react_namespaceObject.useRef)(null);
56
65
  const committedRef = (0, external_react_namespaceObject.useRef)(value);
57
66
  const caretRef = (0, external_react_namespaceObject.useRef)(null);
67
+ const modeControlRef = (0, external_react_namespaceObject.useRef)(null);
68
+ const setModeControl = (0, external_react_namespaceObject.useCallback)((el)=>{
69
+ modeControlRef.current = el;
70
+ }, []);
58
71
  const [datePopoverOpen, setDatePopoverOpen] = (0, external_react_namespaceObject.useState)(false);
59
72
  const [selectOpen, setSelectOpen] = (0, external_react_namespaceObject.useState)(false);
73
+ const [labelDraft, setLabelDraft] = (0, external_react_namespaceObject.useState)(null);
74
+ const [pendingSwitch, setPendingSwitch] = (0, external_react_namespaceObject.useState)();
75
+ const variablePicker = (0, external_react_namespaceObject.useMemo)(()=>(0, external_utils_cjs_namespaceObject.toVariablePickerSource)(variables), [
76
+ variables
77
+ ]);
60
78
  const fieldId = id ?? generatedId;
61
79
  const validationId = errorId ?? `${fieldId}-error`;
62
80
  const typeMeta = external_types_cjs_namespaceObject.FIELD_TYPE_META[fieldType];
@@ -70,6 +88,7 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
70
88
  id: 'clear',
71
89
  label: strings.clearValue,
72
90
  icon: external_lucide_react_namespaceObject.Trash2,
91
+ destructive: true,
73
92
  onSelect: more.onClear
74
93
  }
75
94
  ] : [],
@@ -82,20 +101,44 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
82
101
  }
83
102
  ] : []
84
103
  ];
104
+ const valueModeStrings = {
105
+ ...strings.valueModes,
106
+ literalTitle: strings.literalLabels[fieldType] ?? typeMeta.fixedLabel,
107
+ expressionTitle: strings.expressionLabel,
108
+ expressionDescription: strings.expressionDescription,
109
+ fieldActions: strings.moreActionsAriaLabel
110
+ };
111
+ const focusControlOnClose = (0, external_react_namespaceObject.useRef)(false);
112
+ const keepControlFocus = (event)=>{
113
+ if (!focusControlOnClose.current) return;
114
+ focusControlOnClose.current = false;
115
+ event.preventDefault();
116
+ (valueInputRef.current ?? modeControlRef.current)?.focus();
117
+ };
118
+ const selectMode = (next)=>{
119
+ if (!onModeChange) return;
120
+ const confirm = next !== mode && confirmModeChange?.(mode, next);
121
+ if (confirm) return void setPendingSwitch({
122
+ ...true === confirm ? {} : confirm,
123
+ to: next
124
+ });
125
+ focusControlOnClose.current = next !== mode;
126
+ onModeChange(next);
127
+ };
128
+ const switchable = !!onModeChange && valueModes.length > 1;
85
129
  const builtInMenu = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(field_menu_cjs_namespaceObject.FieldMenu, {
86
130
  mode: mode,
87
- onSelect: (next)=>onModeChange?.(next),
88
- modesDisabled: !onModeChange && menuActions.length > 0,
89
- disabled: disabled || !onModeChange && 0 === menuActions.length,
131
+ modes: [
132
+ ...valueModes
133
+ ],
134
+ onSelect: selectMode,
135
+ modesDisabled: !switchable && menuActions.length > 0,
136
+ disabled: disabled || !switchable && 0 === menuActions.length,
90
137
  actions: menuActions,
91
138
  triggerLabel: strings.valueModeAriaLabel,
92
139
  literalDescription: strings.literalDescriptions[fieldType] ?? typeMeta.fixedDescription,
93
- strings: {
94
- literalTitle: strings.literalLabels[fieldType] ?? typeMeta.fixedLabel,
95
- expressionTitle: strings.expressionLabel,
96
- expressionDescription: strings.expressionDescription,
97
- fieldActions: strings.moreActionsAriaLabel
98
- }
140
+ strings: valueModeStrings,
141
+ onCloseAutoFocus: keepControlFocus
99
142
  });
100
143
  const controlProps = {
101
144
  id: fieldId,
@@ -112,11 +155,14 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
112
155
  'data-slot': 'input-group-control'
113
156
  };
114
157
  const modeControl = renderModeControl?.(mode, controlProps) ?? null;
158
+ const builtInVariable = null === modeControl && 'variable' === mode;
159
+ const builtInPrompt = null === modeControl && 'prompt' === mode;
115
160
  const modeOnMount = (0, external_react_namespaceObject.useRef)(mode);
116
161
  (0, external_react_namespaceObject.useEffect)(()=>{
117
162
  if (modeOnMount.current === mode) return;
118
163
  modeOnMount.current = mode;
119
- valueInputRef.current?.focus();
164
+ const frame = requestAnimationFrame(()=>(valueInputRef.current ?? modeControlRef.current)?.focus());
165
+ return ()=>cancelAnimationFrame(frame);
120
166
  }, [
121
167
  mode
122
168
  ]);
@@ -279,6 +325,11 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
279
325
  selected: (0, external_utils_cjs_namespaceObject.parseListValue)(value),
280
326
  onChange: (selected)=>editableOnValueChange?.(JSON.stringify(selected)),
281
327
  placeholder: strings.selectOptions,
328
+ searchPlaceholder: strings.multiSelectSearchPlaceholder,
329
+ emptyMessage: strings.multiSelectEmpty,
330
+ clearAllText: strings.multiSelectClearAll,
331
+ strings: strings.multiSelect,
332
+ overflow: "collapse",
282
333
  disabled: !editableOnValueChange,
283
334
  onBlur: onValueBlur
284
335
  }) : 'textarea' === fieldType ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupTextarea, {
@@ -292,11 +343,60 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
292
343
  type: 'integer' === fieldType || 'double' === fieldType ? 'number' : 'text',
293
344
  step: 'double' === fieldType ? 'any' : void 0
294
345
  });
346
+ const canPickVariable = !disabled && (!!onInsertVariable || !!onValueChange);
347
+ const variableControl = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_variable_value_control_cjs_namespaceObject.VariableValueControl, {
348
+ id: fieldId,
349
+ value: value,
350
+ onChange: (reference, item)=>onInsertVariable && item ? onInsertVariable(variablePicker.resolve(item), {
351
+ value,
352
+ caret: null
353
+ }) : onValueChange?.(reference),
354
+ onBlur: onValueBlur,
355
+ inputRef: setModeControl,
356
+ variables: variablePicker.items,
357
+ disabled: !canPickVariable,
358
+ placeholder: placeholder,
359
+ strings: strings.valueModes,
360
+ "aria-describedby": controlProps['aria-describedby']
361
+ });
362
+ const promptControl = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_prompt_value_control_cjs_namespaceObject.PromptValueControl, {
363
+ id: fieldId,
364
+ value: value,
365
+ onChange: (next)=>editableOnValueChange?.(next),
366
+ onBlur: onValueBlur,
367
+ inputRef: setModeControl,
368
+ disabled: !editableOnValueChange,
369
+ placeholder: placeholder,
370
+ strings: strings.valueModes,
371
+ "aria-describedby": controlProps['aria-describedby']
372
+ });
373
+ const editableLabel = 'string' == typeof label && onLabelChange ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
374
+ className: (0, index_cjs_namespaceObject.cn)('flex min-w-0 items-center', field_header_cjs_namespaceObject.GROW_WHILE_EDITING),
375
+ children: [
376
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_editable_text_cjs_namespaceObject.EditableText, {
377
+ size: "label",
378
+ value: labelDraft ?? label,
379
+ placeholder: strings.labelPlaceholder,
380
+ "aria-label": strings.labelAriaLabel,
381
+ editing: isEditingLabel,
382
+ onEditingChange: onIsEditingLabelChange,
383
+ disabled: disabled,
384
+ onChange: (next)=>setLabelDraft(next === label ? null : next),
385
+ onSubmit: (next)=>{
386
+ setLabelDraft(null);
387
+ onLabelChange(next);
388
+ }
389
+ }),
390
+ required && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_label_cjs_namespaceObject.RequiredIndicator, {})
391
+ ]
392
+ }) : void 0;
295
393
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
296
394
  className: (0, index_cjs_namespaceObject.cn)('@container group flex flex-col gap-1.5 [&>[data-slot=form-field-error]]:mt-0', className),
297
395
  children: [
298
396
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(field_header_cjs_namespaceObject.FieldHeader, {
299
- label: label,
397
+ label: editableLabel ?? label,
398
+ labelAddon: labelAddon,
399
+ tooltip: tooltip,
300
400
  fieldId: fieldId,
301
401
  fieldLabel: fieldLabel,
302
402
  required: required,
@@ -309,9 +409,9 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
309
409
  isExpression: 'expression' === mode,
310
410
  showFieldActions: showFieldActions,
311
411
  onValueChange: editableOnValueChange,
312
- variables: variables,
412
+ variables: variablePicker,
313
413
  onGenerateWithAi: onGenerateWithAi,
314
- onInsertVariable: (variable)=>onInsertVariable ? onInsertVariable(variable, {
414
+ onInsertVariable: builtInVariable ? void 0 : (variable)=>onInsertVariable ? onInsertVariable(variable, {
315
415
  value,
316
416
  caret: caretRef.current
317
417
  }) : insertVariableAtCaret(variable.value),
@@ -322,7 +422,8 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
322
422
  error: error,
323
423
  errorId: validationId,
324
424
  disabled: disabled,
325
- layout: 'literal' === mode && ('file' === fieldType || 'multi-select' === fieldType || 'textarea' === fieldType) ? 'grow' : 'row',
425
+ variant: builtInPrompt ? 'agent' : void 0,
426
+ layout: builtInPrompt || 'literal' === mode && ('file' === fieldType || 'textarea' === fieldType) ? 'grow' : 'row',
326
427
  children: [
327
428
  (showLock || void 0 !== leadingAddon) && null !== leadingAddon && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupAddon, {
328
429
  align: "inline-start",
@@ -336,7 +437,7 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
336
437
  modeControl ?? ('expression' === mode ? renderExpressionEditor ? renderExpressionEditor(controlProps) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupInput, {
337
438
  ...textInputProps,
338
439
  className: "font-mono"
339
- }) : literalControl),
440
+ }) : builtInVariable ? variableControl : builtInPrompt ? promptControl : literalControl),
340
441
  null !== trailingAddon && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupAddon, {
341
442
  align: "inline-end",
342
443
  className: "cursor-default",
@@ -344,7 +445,23 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
344
445
  })
345
446
  ]
346
447
  }),
347
- belowValue
448
+ belowValue,
449
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(value_mode_switch_dialog_cjs_namespaceObject.ValueModeSwitchDialog, {
450
+ open: !!pendingSwitch,
451
+ title: pendingSwitch?.title,
452
+ description: pendingSwitch?.description,
453
+ confirmLabel: pendingSwitch?.confirmLabel,
454
+ strings: strings.valueModes,
455
+ onCancel: ()=>setPendingSwitch(void 0),
456
+ onConfirm: ()=>{
457
+ if (pendingSwitch && !disabled) {
458
+ focusControlOnClose.current = true;
459
+ onModeChange?.(pendingSwitch.to);
460
+ }
461
+ setPendingSwitch(void 0);
462
+ },
463
+ onCloseAutoFocus: keepControlFocus
464
+ })
348
465
  ]
349
466
  });
350
467
  }
@@ -10,11 +10,14 @@ import type { QuickFormFieldProps } from './types';
10
10
  * form-field anatomy (`FormField`, `FormFieldLabel`, `InputGroup`, …) or
11
11
  * describe them to `MetadataForm`.
12
12
  *
13
- * - Literal and expression have built-in controls; `renderModeControl`
14
- * supplies the control for any mode, and `variable` / `prompt` need it.
13
+ * - Every mode has a built-in control: `variable` is a picker over
14
+ * `variables`, `prompt` an agent textarea. `valueModes` chooses which the
15
+ * menu offers, and `renderModeControl` replaces the control for any mode.
16
+ * - `confirmModeChange` asks before a switch the consumer knows is lossy.
15
17
  * - `locked` is configuration the author sets, so the value stays editable;
16
18
  * `disabled` is what stops the author editing the field.
17
19
  * - `fieldTypes` chooses which types the picker offers.
20
+ * - `onLabelChange` makes a string `label` editable in place.
18
21
  * - Insert variable renders `variables` as supplied and splices at the caret;
19
22
  * `onInsertVariable` takes over what inserting means.
20
23
  * - Enter commits through `onValueBlur`, Escape restores the value as of focus.
@@ -26,4 +29,4 @@ import type { QuickFormFieldProps } from './types';
26
29
  * AI-assist button renders only with `onGenerateWithAi`, and file uploads
27
30
  * aren't persisted anywhere.
28
31
  */
29
- export declare function QuickFormField({ value, onValueChange, onValueBlur, locked, onLockedChange, showLock, disabled, leadingAddon, trailingAddon, more, mode, onModeChange, renderExpressionEditor, renderModeControl, fieldType, fieldTypes, onFieldTypeChange, required, onRequiredChange, label, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions, options, onGenerateWithAi, onInsertVariable, variables, id, className, }: QuickFormFieldProps): import("react/jsx-runtime").JSX.Element;
32
+ export declare function QuickFormField({ value, onValueChange, onValueBlur, locked, onLockedChange, showLock, disabled, leadingAddon, trailingAddon, more, mode, onModeChange, valueModes, confirmModeChange, renderExpressionEditor, renderModeControl, fieldType, fieldTypes, onFieldTypeChange, required, onRequiredChange, label, onLabelChange, isEditingLabel, onIsEditingLabelChange, labelAddon, tooltip, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions, options, onGenerateWithAi, onInsertVariable, variables, id, className, }: QuickFormFieldProps): import("react/jsx-runtime").JSX.Element;
@@ -3,20 +3,29 @@ import { RefreshCw, Trash2 } from "lucide-react";
3
3
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { Calendar } from "../calendar.js";
5
5
  import { DateTimePicker } from "../datetime-picker.js";
6
+ import { EditableText } from "../editable-text.js";
6
7
  import { FileUpload } from "../file-upload.js";
7
8
  import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupTextarea } from "../input-group.js";
9
+ import { RequiredIndicator } from "../label.js";
8
10
  import { MultiSelect } from "../multi-select.js";
9
11
  import { Popover, PopoverContent, PopoverTrigger } from "../popover.js";
12
+ import { PromptValueControl } from "../prompt-value-control.js";
10
13
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select.js";
11
14
  import { Switch } from "../switch.js";
15
+ import { VariableValueControl } from "../variable-value-control.js";
12
16
  import { cn } from "../../../lib/index.js";
13
17
  import { toDateValue } from "../../../lib/date-value.js";
14
18
  import { FieldMenu } from "../field-addons/field-menu.js";
15
- import { FieldHeader } from "./components/field-header.js";
19
+ import { ValueModeSwitchDialog } from "../field-addons/value-mode-switch-dialog.js";
20
+ import { FieldHeader, GROW_WHILE_EDITING } from "./components/field-header.js";
16
21
  import { LockToggleButton } from "./components/lock-toggle-button.js";
17
22
  import { DEFAULT_QUICK_FORM_FIELD_STRINGS, FIELD_TYPE_META } from "./types.js";
18
- import { DEFAULT_SELECT_OPTIONS, formatDateValue, parseListValue, toDateOnlyString } from "./utils.js";
19
- function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, showLock = true, disabled = false, leadingAddon, trailingAddon, more, mode = 'literal', onModeChange, renderExpressionEditor, renderModeControl, fieldType = 'string', fieldTypes, onFieldTypeChange, required, onRequiredChange, label, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions = true, options = DEFAULT_SELECT_OPTIONS, onGenerateWithAi, onInsertVariable, variables = [], id, className }) {
23
+ import { DEFAULT_SELECT_OPTIONS, formatDateValue, parseListValue, toDateOnlyString, toVariablePickerSource } from "./utils.js";
24
+ const DEFAULT_VALUE_MODES = [
25
+ 'literal',
26
+ 'expression'
27
+ ];
28
+ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, showLock = true, disabled = false, leadingAddon, trailingAddon, more, mode = 'literal', onModeChange, valueModes = DEFAULT_VALUE_MODES, confirmModeChange, renderExpressionEditor, renderModeControl, fieldType = 'string', fieldTypes, onFieldTypeChange, required, onRequiredChange, label, onLabelChange, isEditingLabel, onIsEditingLabelChange, labelAddon, tooltip, strings: stringOverrides, placeholder, error, errorId, belowValue, fileUploadAriaLabel, headerActions, compact, showFieldActions = true, options = DEFAULT_SELECT_OPTIONS, onGenerateWithAi, onInsertVariable, variables = [], id, className }) {
20
29
  const strings = useMemo(()=>({
21
30
  ...DEFAULT_QUICK_FORM_FIELD_STRINGS,
22
31
  ...stringOverrides
@@ -27,8 +36,17 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
27
36
  const valueInputRef = useRef(null);
28
37
  const committedRef = useRef(value);
29
38
  const caretRef = useRef(null);
39
+ const modeControlRef = useRef(null);
40
+ const setModeControl = useCallback((el)=>{
41
+ modeControlRef.current = el;
42
+ }, []);
30
43
  const [datePopoverOpen, setDatePopoverOpen] = useState(false);
31
44
  const [selectOpen, setSelectOpen] = useState(false);
45
+ const [labelDraft, setLabelDraft] = useState(null);
46
+ const [pendingSwitch, setPendingSwitch] = useState();
47
+ const variablePicker = useMemo(()=>toVariablePickerSource(variables), [
48
+ variables
49
+ ]);
32
50
  const fieldId = id ?? generatedId;
33
51
  const validationId = errorId ?? `${fieldId}-error`;
34
52
  const typeMeta = FIELD_TYPE_META[fieldType];
@@ -42,6 +60,7 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
42
60
  id: 'clear',
43
61
  label: strings.clearValue,
44
62
  icon: Trash2,
63
+ destructive: true,
45
64
  onSelect: more.onClear
46
65
  }
47
66
  ] : [],
@@ -54,20 +73,44 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
54
73
  }
55
74
  ] : []
56
75
  ];
76
+ const valueModeStrings = {
77
+ ...strings.valueModes,
78
+ literalTitle: strings.literalLabels[fieldType] ?? typeMeta.fixedLabel,
79
+ expressionTitle: strings.expressionLabel,
80
+ expressionDescription: strings.expressionDescription,
81
+ fieldActions: strings.moreActionsAriaLabel
82
+ };
83
+ const focusControlOnClose = useRef(false);
84
+ const keepControlFocus = (event)=>{
85
+ if (!focusControlOnClose.current) return;
86
+ focusControlOnClose.current = false;
87
+ event.preventDefault();
88
+ (valueInputRef.current ?? modeControlRef.current)?.focus();
89
+ };
90
+ const selectMode = (next)=>{
91
+ if (!onModeChange) return;
92
+ const confirm = next !== mode && confirmModeChange?.(mode, next);
93
+ if (confirm) return void setPendingSwitch({
94
+ ...true === confirm ? {} : confirm,
95
+ to: next
96
+ });
97
+ focusControlOnClose.current = next !== mode;
98
+ onModeChange(next);
99
+ };
100
+ const switchable = !!onModeChange && valueModes.length > 1;
57
101
  const builtInMenu = /*#__PURE__*/ jsx(FieldMenu, {
58
102
  mode: mode,
59
- onSelect: (next)=>onModeChange?.(next),
60
- modesDisabled: !onModeChange && menuActions.length > 0,
61
- disabled: disabled || !onModeChange && 0 === menuActions.length,
103
+ modes: [
104
+ ...valueModes
105
+ ],
106
+ onSelect: selectMode,
107
+ modesDisabled: !switchable && menuActions.length > 0,
108
+ disabled: disabled || !switchable && 0 === menuActions.length,
62
109
  actions: menuActions,
63
110
  triggerLabel: strings.valueModeAriaLabel,
64
111
  literalDescription: strings.literalDescriptions[fieldType] ?? typeMeta.fixedDescription,
65
- strings: {
66
- literalTitle: strings.literalLabels[fieldType] ?? typeMeta.fixedLabel,
67
- expressionTitle: strings.expressionLabel,
68
- expressionDescription: strings.expressionDescription,
69
- fieldActions: strings.moreActionsAriaLabel
70
- }
112
+ strings: valueModeStrings,
113
+ onCloseAutoFocus: keepControlFocus
71
114
  });
72
115
  const controlProps = {
73
116
  id: fieldId,
@@ -84,11 +127,14 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
84
127
  'data-slot': 'input-group-control'
85
128
  };
86
129
  const modeControl = renderModeControl?.(mode, controlProps) ?? null;
130
+ const builtInVariable = null === modeControl && 'variable' === mode;
131
+ const builtInPrompt = null === modeControl && 'prompt' === mode;
87
132
  const modeOnMount = useRef(mode);
88
133
  useEffect(()=>{
89
134
  if (modeOnMount.current === mode) return;
90
135
  modeOnMount.current = mode;
91
- valueInputRef.current?.focus();
136
+ const frame = requestAnimationFrame(()=>(valueInputRef.current ?? modeControlRef.current)?.focus());
137
+ return ()=>cancelAnimationFrame(frame);
92
138
  }, [
93
139
  mode
94
140
  ]);
@@ -251,6 +297,11 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
251
297
  selected: parseListValue(value),
252
298
  onChange: (selected)=>editableOnValueChange?.(JSON.stringify(selected)),
253
299
  placeholder: strings.selectOptions,
300
+ searchPlaceholder: strings.multiSelectSearchPlaceholder,
301
+ emptyMessage: strings.multiSelectEmpty,
302
+ clearAllText: strings.multiSelectClearAll,
303
+ strings: strings.multiSelect,
304
+ overflow: "collapse",
254
305
  disabled: !editableOnValueChange,
255
306
  onBlur: onValueBlur
256
307
  }) : 'textarea' === fieldType ? /*#__PURE__*/ jsx(InputGroupTextarea, {
@@ -264,11 +315,60 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
264
315
  type: 'integer' === fieldType || 'double' === fieldType ? 'number' : 'text',
265
316
  step: 'double' === fieldType ? 'any' : void 0
266
317
  });
318
+ const canPickVariable = !disabled && (!!onInsertVariable || !!onValueChange);
319
+ const variableControl = /*#__PURE__*/ jsx(VariableValueControl, {
320
+ id: fieldId,
321
+ value: value,
322
+ onChange: (reference, item)=>onInsertVariable && item ? onInsertVariable(variablePicker.resolve(item), {
323
+ value,
324
+ caret: null
325
+ }) : onValueChange?.(reference),
326
+ onBlur: onValueBlur,
327
+ inputRef: setModeControl,
328
+ variables: variablePicker.items,
329
+ disabled: !canPickVariable,
330
+ placeholder: placeholder,
331
+ strings: strings.valueModes,
332
+ "aria-describedby": controlProps['aria-describedby']
333
+ });
334
+ const promptControl = /*#__PURE__*/ jsx(PromptValueControl, {
335
+ id: fieldId,
336
+ value: value,
337
+ onChange: (next)=>editableOnValueChange?.(next),
338
+ onBlur: onValueBlur,
339
+ inputRef: setModeControl,
340
+ disabled: !editableOnValueChange,
341
+ placeholder: placeholder,
342
+ strings: strings.valueModes,
343
+ "aria-describedby": controlProps['aria-describedby']
344
+ });
345
+ const editableLabel = 'string' == typeof label && onLabelChange ? /*#__PURE__*/ jsxs("span", {
346
+ className: cn('flex min-w-0 items-center', GROW_WHILE_EDITING),
347
+ children: [
348
+ /*#__PURE__*/ jsx(EditableText, {
349
+ size: "label",
350
+ value: labelDraft ?? label,
351
+ placeholder: strings.labelPlaceholder,
352
+ "aria-label": strings.labelAriaLabel,
353
+ editing: isEditingLabel,
354
+ onEditingChange: onIsEditingLabelChange,
355
+ disabled: disabled,
356
+ onChange: (next)=>setLabelDraft(next === label ? null : next),
357
+ onSubmit: (next)=>{
358
+ setLabelDraft(null);
359
+ onLabelChange(next);
360
+ }
361
+ }),
362
+ required && /*#__PURE__*/ jsx(RequiredIndicator, {})
363
+ ]
364
+ }) : void 0;
267
365
  return /*#__PURE__*/ jsxs("div", {
268
366
  className: cn('@container group flex flex-col gap-1.5 [&>[data-slot=form-field-error]]:mt-0', className),
269
367
  children: [
270
368
  /*#__PURE__*/ jsx(FieldHeader, {
271
- label: label,
369
+ label: editableLabel ?? label,
370
+ labelAddon: labelAddon,
371
+ tooltip: tooltip,
272
372
  fieldId: fieldId,
273
373
  fieldLabel: fieldLabel,
274
374
  required: required,
@@ -281,9 +381,9 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
281
381
  isExpression: 'expression' === mode,
282
382
  showFieldActions: showFieldActions,
283
383
  onValueChange: editableOnValueChange,
284
- variables: variables,
384
+ variables: variablePicker,
285
385
  onGenerateWithAi: onGenerateWithAi,
286
- onInsertVariable: (variable)=>onInsertVariable ? onInsertVariable(variable, {
386
+ onInsertVariable: builtInVariable ? void 0 : (variable)=>onInsertVariable ? onInsertVariable(variable, {
287
387
  value,
288
388
  caret: caretRef.current
289
389
  }) : insertVariableAtCaret(variable.value),
@@ -294,7 +394,8 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
294
394
  error: error,
295
395
  errorId: validationId,
296
396
  disabled: disabled,
297
- layout: 'literal' === mode && ('file' === fieldType || 'multi-select' === fieldType || 'textarea' === fieldType) ? 'grow' : 'row',
397
+ variant: builtInPrompt ? 'agent' : void 0,
398
+ layout: builtInPrompt || 'literal' === mode && ('file' === fieldType || 'textarea' === fieldType) ? 'grow' : 'row',
298
399
  children: [
299
400
  (showLock || void 0 !== leadingAddon) && null !== leadingAddon && /*#__PURE__*/ jsx(InputGroupAddon, {
300
401
  align: "inline-start",
@@ -308,7 +409,7 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
308
409
  modeControl ?? ('expression' === mode ? renderExpressionEditor ? renderExpressionEditor(controlProps) : /*#__PURE__*/ jsx(InputGroupInput, {
309
410
  ...textInputProps,
310
411
  className: "font-mono"
311
- }) : literalControl),
412
+ }) : builtInVariable ? variableControl : builtInPrompt ? promptControl : literalControl),
312
413
  null !== trailingAddon && /*#__PURE__*/ jsx(InputGroupAddon, {
313
414
  align: "inline-end",
314
415
  className: "cursor-default",
@@ -316,7 +417,23 @@ function QuickFormField({ value = '', onValueChange, onValueBlur, locked = true,
316
417
  })
317
418
  ]
318
419
  }),
319
- belowValue
420
+ belowValue,
421
+ /*#__PURE__*/ jsx(ValueModeSwitchDialog, {
422
+ open: !!pendingSwitch,
423
+ title: pendingSwitch?.title,
424
+ description: pendingSwitch?.description,
425
+ confirmLabel: pendingSwitch?.confirmLabel,
426
+ strings: strings.valueModes,
427
+ onCancel: ()=>setPendingSwitch(void 0),
428
+ onConfirm: ()=>{
429
+ if (pendingSwitch && !disabled) {
430
+ focusControlOnClose.current = true;
431
+ onModeChange?.(pendingSwitch.to);
432
+ }
433
+ setPendingSwitch(void 0);
434
+ },
435
+ onCloseAutoFocus: keepControlFocus
436
+ })
320
437
  ]
321
438
  });
322
439
  }
@@ -144,6 +144,9 @@ const DEFAULT_QUICK_FORM_FIELD_STRINGS = {
144
144
  falseLabel: 'False',
145
145
  requiredTooltip: 'Required',
146
146
  requiredAriaLabel: 'Required field',
147
+ labelAriaLabel: 'Field label',
148
+ labelPlaceholder: 'Untitled field',
149
+ tooltipAriaLabel: 'More information',
147
150
  optionalAriaLabel: 'Optional field',
148
151
  insertLabel: 'Insert',
149
152
  insertAriaLabel: 'Insert variable',
@@ -152,9 +155,14 @@ const DEFAULT_QUICK_FORM_FIELD_STRINGS = {
152
155
  valueModeAriaLabel: 'Choose value mode',
153
156
  expressionLabel: 'Expression',
154
157
  expressionDescription: 'Use a JS expression',
158
+ valueModes: {},
155
159
  pickDate: 'Pick a date',
156
160
  selectOption: 'Select an option',
157
161
  selectOptions: 'Select options...',
162
+ multiSelectSearchPlaceholder: 'Search...',
163
+ multiSelectEmpty: 'No items found.',
164
+ multiSelectClearAll: (count)=>`Clear all (${count})`,
165
+ multiSelect: {},
158
166
  moreActionsAriaLabel: 'More value actions',
159
167
  clearValue: 'Clear value',
160
168
  forceRefresh: 'Force refresh',