@uipath/apollo-wind 2.79.1 → 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 (46) hide show
  1. package/dist/components/forms/metadata-form.cjs +3 -2
  2. package/dist/components/forms/metadata-form.js +3 -2
  3. package/dist/components/ui/editable-text.cjs +251 -0
  4. package/dist/components/ui/editable-text.d.ts +48 -0
  5. package/dist/components/ui/editable-text.js +217 -0
  6. package/dist/components/ui/field-actions/ai-assist-action.cjs +7 -5
  7. package/dist/components/ui/field-actions/ai-assist-action.js +7 -5
  8. package/dist/components/ui/field-actions/collapse.cjs +7 -7
  9. package/dist/components/ui/field-actions/collapse.d.ts +6 -3
  10. package/dist/components/ui/field-actions/collapse.js +3 -3
  11. package/dist/components/ui/field-actions/insert-variable-action.cjs +7 -7
  12. package/dist/components/ui/field-actions/insert-variable-action.js +8 -8
  13. package/dist/components/ui/field-addons/field-menu.cjs +2 -1
  14. package/dist/components/ui/field-addons/field-menu.d.ts +6 -1
  15. package/dist/components/ui/field-addons/field-menu.js +2 -1
  16. package/dist/components/ui/field-addons/value-mode-switch-dialog.cjs +2 -1
  17. package/dist/components/ui/field-addons/value-mode-switch-dialog.d.ts +6 -1
  18. package/dist/components/ui/field-addons/value-mode-switch-dialog.js +2 -1
  19. package/dist/components/ui/index.cjs +215 -202
  20. package/dist/components/ui/index.d.ts +1 -0
  21. package/dist/components/ui/index.js +1 -0
  22. package/dist/components/ui/input-group.cjs +7 -3
  23. package/dist/components/ui/input-group.d.ts +1 -1
  24. package/dist/components/ui/input-group.js +7 -3
  25. package/dist/components/ui/quick-form-field/components/field-header.cjs +55 -52
  26. package/dist/components/ui/quick-form-field/components/field-header.d.ts +13 -4
  27. package/dist/components/ui/quick-form-field/components/field-header.js +53 -53
  28. package/dist/components/ui/quick-form-field/index.d.ts +1 -1
  29. package/dist/components/ui/quick-form-field/quick-form-field.cjs +134 -17
  30. package/dist/components/ui/quick-form-field/quick-form-field.d.ts +6 -3
  31. package/dist/components/ui/quick-form-field/quick-form-field.js +136 -19
  32. package/dist/components/ui/quick-form-field/types.cjs +8 -0
  33. package/dist/components/ui/quick-form-field/types.d.ts +81 -14
  34. package/dist/components/ui/quick-form-field/types.js +8 -0
  35. package/dist/components/ui/quick-form-field/utils.cjs +30 -1
  36. package/dist/components/ui/quick-form-field/utils.d.ts +8 -0
  37. package/dist/components/ui/quick-form-field/utils.js +27 -1
  38. package/dist/components/ui/variable-value-control.cjs +7 -4
  39. package/dist/components/ui/variable-value-control.d.ts +5 -1
  40. package/dist/components/ui/variable-value-control.js +7 -4
  41. package/dist/index.cjs +4 -0
  42. package/dist/index.d.ts +3 -1
  43. package/dist/index.js +2 -1
  44. package/dist/styles.css +74 -22
  45. package/dist/tailwind.css +2 -1
  46. package/package.json +1 -1
@@ -587,9 +587,10 @@ const metadata_form_FormSection = /*#__PURE__*/ external_react_default().memo(fu
587
587
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
588
588
  className: isPlain ? dividerClassName : wrapperClassName,
589
589
  children: [
590
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
590
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h3", {
591
+ "data-slot": "form-section-header",
591
592
  className: "flex",
592
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
593
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
593
594
  className: isPlain ? `flex flex-1 items-center justify-start gap-2 pb-4 text-sm font-semibold ${plainTopClassName}` : 'flex flex-1 items-center justify-between py-4 text-sm font-medium',
594
595
  children: section.title
595
596
  })
@@ -548,9 +548,10 @@ const metadata_form_FormSection = /*#__PURE__*/ react.memo(function({ section, c
548
548
  return /*#__PURE__*/ jsxs("div", {
549
549
  className: isPlain ? dividerClassName : wrapperClassName,
550
550
  children: [
551
- /*#__PURE__*/ jsx("div", {
551
+ /*#__PURE__*/ jsx("h3", {
552
+ "data-slot": "form-section-header",
552
553
  className: "flex",
553
- children: /*#__PURE__*/ jsx("div", {
554
+ children: /*#__PURE__*/ jsx("span", {
554
555
  className: isPlain ? `flex flex-1 items-center justify-start gap-2 pb-4 text-sm font-semibold ${plainTopClassName}` : 'flex flex-1 items-center justify-between py-4 text-sm font-medium',
555
556
  children: section.title
556
557
  })
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ EditableText: ()=>EditableText
28
+ });
29
+ const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
+ const external_react_namespaceObject = require("react");
31
+ const external_form_field_cjs_namespaceObject = require("./form-field.cjs");
32
+ const external_tooltip_cjs_namespaceObject = require("./tooltip.cjs");
33
+ const index_cjs_namespaceObject = require("../../lib/index.cjs");
34
+ const useIsomorphicLayoutEffect = "u" < typeof window ? external_react_namespaceObject.useEffect : external_react_namespaceObject.useLayoutEffect;
35
+ const stripNewlines = (text)=>text.replace(/\n+/g, ' ');
36
+ const READ_CLASS = {
37
+ label: 'text-xs font-medium leading-4 text-foreground',
38
+ lg: 'text-base font-semibold leading-5 tracking-[-0.3px] text-foreground',
39
+ sm: 'text-xs leading-4 text-foreground-muted'
40
+ };
41
+ const EDIT_CLASS = {
42
+ label: 'text-xs font-medium leading-4',
43
+ lg: 'text-base font-semibold leading-5 tracking-[-0.3px]',
44
+ sm: 'text-xs leading-4'
45
+ };
46
+ const LINE_HEIGHT = {
47
+ label: 16,
48
+ lg: 20,
49
+ sm: 16
50
+ };
51
+ const VERTICAL_PADDING = 4;
52
+ const CLAMP_CLASS = 'line-clamp-[var(--editable-text-lines)] whitespace-pre-line wrap-break-word';
53
+ const INTERACTIVE_CLASS = 'rounded px-1.5 py-0.5 -mx-1.5';
54
+ const EDITOR_SPACING_CLASS = 'rounded px-1.5 py-0.5 -ml-1.5';
55
+ const READ_MAX_WIDTH_CLASS = 'max-w-[calc(100%+--spacing(3))]';
56
+ const ERROR_RING_CLASS = 'ring-1 ring-error';
57
+ function TruncationTooltip({ content, multiline, children }) {
58
+ const triggerRef = external_react_namespaceObject.useRef(null);
59
+ const setTrigger = external_react_namespaceObject.useCallback((node)=>{
60
+ triggerRef.current = node;
61
+ }, []);
62
+ const [open, setOpen] = external_react_namespaceObject.useState(false);
63
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_tooltip_cjs_namespaceObject.TooltipProvider, {
64
+ delayDuration: 700,
65
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_tooltip_cjs_namespaceObject.Tooltip, {
66
+ open: open,
67
+ onOpenChange: (next)=>{
68
+ const node = triggerRef.current;
69
+ setOpen(next && !!node && (node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight));
70
+ },
71
+ children: [
72
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_tooltip_cjs_namespaceObject.TooltipTrigger, {
73
+ asChild: true,
74
+ ref: setTrigger,
75
+ children: children
76
+ }),
77
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_tooltip_cjs_namespaceObject.TooltipPortal, {
78
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_tooltip_cjs_namespaceObject.TooltipContent, {
79
+ className: (0, index_cjs_namespaceObject.cn)('max-w-80 wrap-break-word', multiline && 'whitespace-pre-line'),
80
+ children: content
81
+ })
82
+ })
83
+ ]
84
+ })
85
+ });
86
+ }
87
+ function EditableText({ value, placeholder, size = 'lg', multiline, maxLines = 3, onChange, onSubmit, editing: editingProp, onEditingChange, disabled, truncationTooltip = true, error, 'aria-label': ariaLabel, className, 'data-testid': dataTestId }) {
88
+ const allowNewlines = true === multiline;
89
+ const editable = !!onChange && !!onSubmit;
90
+ const [editingState, setEditingState] = external_react_namespaceObject.useState(false);
91
+ const controlled = void 0 !== editingProp;
92
+ const requested = controlled ? editingProp : editingState;
93
+ const isEditing = requested && editable && !disabled;
94
+ const setEditing = external_react_namespaceObject.useCallback((next)=>{
95
+ if (!controlled) setEditingState(next);
96
+ onEditingChange?.(next);
97
+ }, [
98
+ controlled,
99
+ onEditingChange
100
+ ]);
101
+ const inputRef = external_react_namespaceObject.useRef(null);
102
+ const openedWith = external_react_namespaceObject.useRef(value);
103
+ const latestValue = external_react_namespaceObject.useRef(value);
104
+ latestValue.current = value;
105
+ const errorId = `editable-text-${external_react_namespaceObject.useId().replace(/:/g, '')}-error`;
106
+ const hasError = !!error;
107
+ const describedBy = hasError ? errorId : void 0;
108
+ useIsomorphicLayoutEffect(()=>{
109
+ if (disabled && requested) setEditing(false);
110
+ }, [
111
+ disabled,
112
+ requested,
113
+ setEditing
114
+ ]);
115
+ useIsomorphicLayoutEffect(()=>{
116
+ if (!isEditing) return;
117
+ openedWith.current = latestValue.current;
118
+ inputRef.current?.focus();
119
+ inputRef.current?.select();
120
+ }, [
121
+ isEditing
122
+ ]);
123
+ const cancel = external_react_namespaceObject.useCallback(()=>{
124
+ setEditing(false);
125
+ if (openedWith.current !== value) onChange?.(openedWith.current);
126
+ }, [
127
+ value,
128
+ onChange,
129
+ setEditing
130
+ ]);
131
+ const commit = external_react_namespaceObject.useCallback(()=>{
132
+ const next = value.trim();
133
+ setEditing(false);
134
+ if (next !== value) onChange?.(next);
135
+ if (next !== openedWith.current) onSubmit?.(next);
136
+ }, [
137
+ value,
138
+ onChange,
139
+ onSubmit,
140
+ setEditing
141
+ ]);
142
+ const handleKeyDown = external_react_namespaceObject.useCallback((e)=>{
143
+ if ('Enter' !== e.key || allowNewlines && e.shiftKey) {
144
+ if ('Escape' === e.key) {
145
+ e.preventDefault();
146
+ cancel();
147
+ }
148
+ } else {
149
+ e.preventDefault();
150
+ commit();
151
+ }
152
+ e.stopPropagation();
153
+ }, [
154
+ commit,
155
+ cancel,
156
+ allowNewlines
157
+ ]);
158
+ const editorMaxHeight = multiline ? {
159
+ maxHeight: maxLines * LINE_HEIGHT[size] + VERTICAL_PADDING
160
+ } : void 0;
161
+ const readClampStyle = multiline ? {
162
+ '--editable-text-lines': maxLines
163
+ } : void 0;
164
+ const readClampClass = multiline ? CLAMP_CLASS : 'block truncate';
165
+ const withTooltip = (trigger)=>truncationTooltip && (value || placeholder) ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(TruncationTooltip, {
166
+ content: value || placeholder,
167
+ multiline: !!multiline,
168
+ children: trigger
169
+ }) : trigger;
170
+ const message = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_form_field_cjs_namespaceObject.FormFieldError, {
171
+ id: errorId,
172
+ "data-slot": "editable-text-error",
173
+ className: "-ml-1 mt-1",
174
+ children: error
175
+ });
176
+ if (!editable) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
177
+ children: [
178
+ withTooltip(/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
179
+ "data-slot": "editable-text",
180
+ "data-testid": dataTestId,
181
+ "aria-describedby": describedBy,
182
+ style: readClampStyle,
183
+ className: (0, index_cjs_namespaceObject.cn)(readClampClass, READ_CLASS[size], !value && 'text-foreground-subtle', hasError && (0, index_cjs_namespaceObject.cn)(INTERACTIVE_CLASS, ERROR_RING_CLASS), className),
184
+ children: value || placeholder
185
+ })),
186
+ message
187
+ ]
188
+ });
189
+ if (isEditing) {
190
+ const sharedProps = {
191
+ 'data-slot': 'editable-text-input',
192
+ 'data-testid': dataTestId ? `${dataTestId}-input` : void 0,
193
+ value,
194
+ placeholder,
195
+ 'aria-label': ariaLabel,
196
+ 'aria-describedby': describedBy,
197
+ 'aria-errormessage': hasError ? errorId : void 0,
198
+ 'aria-invalid': hasError || void 0,
199
+ onKeyDown: handleKeyDown,
200
+ onBlur: commit,
201
+ className: (0, index_cjs_namespaceObject.cn)('w-full min-w-0 border-none bg-surface-overlay text-foreground outline-none ring-1', hasError ? 'ring-error' : 'ring-brand', EDITOR_SPACING_CLASS, EDIT_CLASS[size], className)
202
+ };
203
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
204
+ children: [
205
+ multiline ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("textarea", {
206
+ ...sharedProps,
207
+ ref: inputRef,
208
+ rows: 1,
209
+ style: editorMaxHeight,
210
+ className: (0, index_cjs_namespaceObject.cn)(sharedProps.className, 'field-sizing-content max-w-full resize-none overflow-y-auto wrap-break-word'),
211
+ onChange: (e)=>onChange?.(allowNewlines ? e.target.value : stripNewlines(e.target.value))
212
+ }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("input", {
213
+ ...sharedProps,
214
+ ref: inputRef,
215
+ autoComplete: "off",
216
+ onChange: (e)=>onChange?.(e.target.value)
217
+ }),
218
+ message
219
+ ]
220
+ });
221
+ }
222
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
223
+ children: [
224
+ withTooltip(/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
225
+ type: "button",
226
+ "data-slot": "editable-text",
227
+ "data-testid": dataTestId,
228
+ "aria-label": ariaLabel && `${ariaLabel}: ${value || placeholder || ''}`,
229
+ "aria-describedby": describedBy,
230
+ "aria-errormessage": hasError ? errorId : void 0,
231
+ "aria-invalid": hasError || void 0,
232
+ "aria-disabled": disabled || void 0,
233
+ onClick: ()=>{
234
+ if (disabled) return;
235
+ setEditing(true);
236
+ },
237
+ style: readClampStyle,
238
+ className: (0, index_cjs_namespaceObject.cn)('cursor-text border-none bg-transparent text-left transition hover:bg-surface-overlay', READ_MAX_WIDTH_CLASS, 'aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:hover:bg-transparent', readClampClass, INTERACTIVE_CLASS, READ_CLASS[size], !value && 'text-foreground-subtle', hasError && ERROR_RING_CLASS, className),
239
+ children: value || placeholder
240
+ })),
241
+ message
242
+ ]
243
+ });
244
+ }
245
+ exports.EditableText = __webpack_exports__.EditableText;
246
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
247
+ "EditableText"
248
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
249
+ Object.defineProperty(exports, '__esModule', {
250
+ value: true
251
+ });
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ /** `label` matches a field label; `sm` and `lg` a secondary line and a title. */
3
+ export type EditableTextSize = 'label' | 'sm' | 'lg';
4
+ export interface EditableTextProps {
5
+ /** The text on screen, in both modes: this is a controlled field, so an edit shows up only once `onChange` has been applied here. */
6
+ value: string;
7
+ placeholder?: string;
8
+ /** Defaults to `lg`. */
9
+ size?: EditableTextSize;
10
+ /**
11
+ * Text layout. `true` accepts newlines (Shift+Enter); `'wrap'` wraps across lines but keeps the
12
+ * value single-line, so every Enter commits and pasted newlines collapse. Enter always commits.
13
+ */
14
+ multiline?: boolean | 'wrap';
15
+ /** Visible-line ceiling when `multiline`. The editor scrolls past it. Defaults to 3. */
16
+ maxLines?: number;
17
+ /** Fires on every keystroke with the text as typed, like any controlled input. Pair with `onSubmit`: both are required to make the text editable, and `value` has to follow this callback or the field won't accept input. Escape reports the text held when the editor opened, so the owner reverts through this same path. */
18
+ onChange?: (next: string) => void;
19
+ /** Fires on Enter or blur with the trimmed `value`, and only when it differs from the text the editor opened with, so a click in and straight back out is silent. The owner decides whether to persist it. */
20
+ onSubmit?: (next: string) => void;
21
+ /**
22
+ * Whether the editor is open, for an owner that holds that state: it opens focused with the text
23
+ * selected, and asks to close through `onEditingChange`. Omit to let the component hold it.
24
+ */
25
+ editing?: boolean;
26
+ /**
27
+ * Called when the editor asks to open (a click) or close (commit, Escape, or going disabled).
28
+ * Required alongside `editing` for the editor to open or close at all.
29
+ */
30
+ onEditingChange?: (editing: boolean) => void;
31
+ /** Locks the text as-is: no edit mode, no commit. Ignored for static text. */
32
+ disabled?: boolean;
33
+ /** Field-specific feedback rendered immediately below the text. */
34
+ error?: React.ReactNode;
35
+ /** Show the full text in a tooltip on hover when it is cut off. On by default. */
36
+ truncationTooltip?: boolean;
37
+ /** Names the editor and its click target. Unused for static text. */
38
+ 'aria-label'?: string;
39
+ className?: string;
40
+ 'data-testid'?: string;
41
+ }
42
+ /**
43
+ * Click-to-edit text, such as a name or title: enters on click, submits on Enter or blur, reverts
44
+ * on Escape. Controlled: the owner holds the text and feeds it back through `value`, which lets it
45
+ * validate what is being typed and render the message through `error`. Renders static text unless
46
+ * both `onChange` and `onSubmit` are given. Text that is cut off shows in full in a tooltip.
47
+ */
48
+ export declare function EditableText({ value, placeholder, size, multiline, maxLines, onChange, onSubmit, editing: editingProp, onEditingChange, disabled, truncationTooltip, error, 'aria-label': ariaLabel, className, 'data-testid': dataTestId, }: EditableTextProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,217 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
3
+ import { FormFieldError } from "./form-field.js";
4
+ import { Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipTrigger } from "./tooltip.js";
5
+ import { cn } from "../../lib/index.js";
6
+ const useIsomorphicLayoutEffect = "u" < typeof window ? useEffect : useLayoutEffect;
7
+ const stripNewlines = (text)=>text.replace(/\n+/g, ' ');
8
+ const READ_CLASS = {
9
+ label: 'text-xs font-medium leading-4 text-foreground',
10
+ lg: 'text-base font-semibold leading-5 tracking-[-0.3px] text-foreground',
11
+ sm: 'text-xs leading-4 text-foreground-muted'
12
+ };
13
+ const EDIT_CLASS = {
14
+ label: 'text-xs font-medium leading-4',
15
+ lg: 'text-base font-semibold leading-5 tracking-[-0.3px]',
16
+ sm: 'text-xs leading-4'
17
+ };
18
+ const LINE_HEIGHT = {
19
+ label: 16,
20
+ lg: 20,
21
+ sm: 16
22
+ };
23
+ const VERTICAL_PADDING = 4;
24
+ const CLAMP_CLASS = 'line-clamp-[var(--editable-text-lines)] whitespace-pre-line wrap-break-word';
25
+ const INTERACTIVE_CLASS = 'rounded px-1.5 py-0.5 -mx-1.5';
26
+ const EDITOR_SPACING_CLASS = 'rounded px-1.5 py-0.5 -ml-1.5';
27
+ const READ_MAX_WIDTH_CLASS = 'max-w-[calc(100%+--spacing(3))]';
28
+ const ERROR_RING_CLASS = 'ring-1 ring-error';
29
+ function TruncationTooltip({ content, multiline, children }) {
30
+ const triggerRef = useRef(null);
31
+ const setTrigger = useCallback((node)=>{
32
+ triggerRef.current = node;
33
+ }, []);
34
+ const [open, setOpen] = useState(false);
35
+ return /*#__PURE__*/ jsx(TooltipProvider, {
36
+ delayDuration: 700,
37
+ children: /*#__PURE__*/ jsxs(Tooltip, {
38
+ open: open,
39
+ onOpenChange: (next)=>{
40
+ const node = triggerRef.current;
41
+ setOpen(next && !!node && (node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight));
42
+ },
43
+ children: [
44
+ /*#__PURE__*/ jsx(TooltipTrigger, {
45
+ asChild: true,
46
+ ref: setTrigger,
47
+ children: children
48
+ }),
49
+ /*#__PURE__*/ jsx(TooltipPortal, {
50
+ children: /*#__PURE__*/ jsx(TooltipContent, {
51
+ className: cn('max-w-80 wrap-break-word', multiline && 'whitespace-pre-line'),
52
+ children: content
53
+ })
54
+ })
55
+ ]
56
+ })
57
+ });
58
+ }
59
+ function EditableText({ value, placeholder, size = 'lg', multiline, maxLines = 3, onChange, onSubmit, editing: editingProp, onEditingChange, disabled, truncationTooltip = true, error, 'aria-label': ariaLabel, className, 'data-testid': dataTestId }) {
60
+ const allowNewlines = true === multiline;
61
+ const editable = !!onChange && !!onSubmit;
62
+ const [editingState, setEditingState] = useState(false);
63
+ const controlled = void 0 !== editingProp;
64
+ const requested = controlled ? editingProp : editingState;
65
+ const isEditing = requested && editable && !disabled;
66
+ const setEditing = useCallback((next)=>{
67
+ if (!controlled) setEditingState(next);
68
+ onEditingChange?.(next);
69
+ }, [
70
+ controlled,
71
+ onEditingChange
72
+ ]);
73
+ const inputRef = useRef(null);
74
+ const openedWith = useRef(value);
75
+ const latestValue = useRef(value);
76
+ latestValue.current = value;
77
+ const errorId = `editable-text-${useId().replace(/:/g, '')}-error`;
78
+ const hasError = !!error;
79
+ const describedBy = hasError ? errorId : void 0;
80
+ useIsomorphicLayoutEffect(()=>{
81
+ if (disabled && requested) setEditing(false);
82
+ }, [
83
+ disabled,
84
+ requested,
85
+ setEditing
86
+ ]);
87
+ useIsomorphicLayoutEffect(()=>{
88
+ if (!isEditing) return;
89
+ openedWith.current = latestValue.current;
90
+ inputRef.current?.focus();
91
+ inputRef.current?.select();
92
+ }, [
93
+ isEditing
94
+ ]);
95
+ const cancel = useCallback(()=>{
96
+ setEditing(false);
97
+ if (openedWith.current !== value) onChange?.(openedWith.current);
98
+ }, [
99
+ value,
100
+ onChange,
101
+ setEditing
102
+ ]);
103
+ const commit = useCallback(()=>{
104
+ const next = value.trim();
105
+ setEditing(false);
106
+ if (next !== value) onChange?.(next);
107
+ if (next !== openedWith.current) onSubmit?.(next);
108
+ }, [
109
+ value,
110
+ onChange,
111
+ onSubmit,
112
+ setEditing
113
+ ]);
114
+ const handleKeyDown = useCallback((e)=>{
115
+ if ('Enter' !== e.key || allowNewlines && e.shiftKey) {
116
+ if ('Escape' === e.key) {
117
+ e.preventDefault();
118
+ cancel();
119
+ }
120
+ } else {
121
+ e.preventDefault();
122
+ commit();
123
+ }
124
+ e.stopPropagation();
125
+ }, [
126
+ commit,
127
+ cancel,
128
+ allowNewlines
129
+ ]);
130
+ const editorMaxHeight = multiline ? {
131
+ maxHeight: maxLines * LINE_HEIGHT[size] + VERTICAL_PADDING
132
+ } : void 0;
133
+ const readClampStyle = multiline ? {
134
+ '--editable-text-lines': maxLines
135
+ } : void 0;
136
+ const readClampClass = multiline ? CLAMP_CLASS : 'block truncate';
137
+ const withTooltip = (trigger)=>truncationTooltip && (value || placeholder) ? /*#__PURE__*/ jsx(TruncationTooltip, {
138
+ content: value || placeholder,
139
+ multiline: !!multiline,
140
+ children: trigger
141
+ }) : trigger;
142
+ const message = /*#__PURE__*/ jsx(FormFieldError, {
143
+ id: errorId,
144
+ "data-slot": "editable-text-error",
145
+ className: "-ml-1 mt-1",
146
+ children: error
147
+ });
148
+ if (!editable) return /*#__PURE__*/ jsxs(Fragment, {
149
+ children: [
150
+ withTooltip(/*#__PURE__*/ jsx("span", {
151
+ "data-slot": "editable-text",
152
+ "data-testid": dataTestId,
153
+ "aria-describedby": describedBy,
154
+ style: readClampStyle,
155
+ className: cn(readClampClass, READ_CLASS[size], !value && 'text-foreground-subtle', hasError && cn(INTERACTIVE_CLASS, ERROR_RING_CLASS), className),
156
+ children: value || placeholder
157
+ })),
158
+ message
159
+ ]
160
+ });
161
+ if (isEditing) {
162
+ const sharedProps = {
163
+ 'data-slot': 'editable-text-input',
164
+ 'data-testid': dataTestId ? `${dataTestId}-input` : void 0,
165
+ value,
166
+ placeholder,
167
+ 'aria-label': ariaLabel,
168
+ 'aria-describedby': describedBy,
169
+ 'aria-errormessage': hasError ? errorId : void 0,
170
+ 'aria-invalid': hasError || void 0,
171
+ onKeyDown: handleKeyDown,
172
+ onBlur: commit,
173
+ className: cn('w-full min-w-0 border-none bg-surface-overlay text-foreground outline-none ring-1', hasError ? 'ring-error' : 'ring-brand', EDITOR_SPACING_CLASS, EDIT_CLASS[size], className)
174
+ };
175
+ return /*#__PURE__*/ jsxs(Fragment, {
176
+ children: [
177
+ multiline ? /*#__PURE__*/ jsx("textarea", {
178
+ ...sharedProps,
179
+ ref: inputRef,
180
+ rows: 1,
181
+ style: editorMaxHeight,
182
+ className: cn(sharedProps.className, 'field-sizing-content max-w-full resize-none overflow-y-auto wrap-break-word'),
183
+ onChange: (e)=>onChange?.(allowNewlines ? e.target.value : stripNewlines(e.target.value))
184
+ }) : /*#__PURE__*/ jsx("input", {
185
+ ...sharedProps,
186
+ ref: inputRef,
187
+ autoComplete: "off",
188
+ onChange: (e)=>onChange?.(e.target.value)
189
+ }),
190
+ message
191
+ ]
192
+ });
193
+ }
194
+ return /*#__PURE__*/ jsxs(Fragment, {
195
+ children: [
196
+ withTooltip(/*#__PURE__*/ jsx("button", {
197
+ type: "button",
198
+ "data-slot": "editable-text",
199
+ "data-testid": dataTestId,
200
+ "aria-label": ariaLabel && `${ariaLabel}: ${value || placeholder || ''}`,
201
+ "aria-describedby": describedBy,
202
+ "aria-errormessage": hasError ? errorId : void 0,
203
+ "aria-invalid": hasError || void 0,
204
+ "aria-disabled": disabled || void 0,
205
+ onClick: ()=>{
206
+ if (disabled) return;
207
+ setEditing(true);
208
+ },
209
+ style: readClampStyle,
210
+ className: cn('cursor-text border-none bg-transparent text-left transition hover:bg-surface-overlay', READ_MAX_WIDTH_CLASS, 'aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:hover:bg-transparent', readClampClass, INTERACTIVE_CLASS, READ_CLASS[size], !value && 'text-foreground-subtle', hasError && ERROR_RING_CLASS, className),
211
+ children: value || placeholder
212
+ })),
213
+ message
214
+ ]
215
+ });
216
+ }
217
+ export { EditableText };
@@ -35,6 +35,7 @@ const external_label_cjs_namespaceObject = require("../label.cjs");
35
35
  const external_popover_cjs_namespaceObject = require("../popover.cjs");
36
36
  const external_textarea_cjs_namespaceObject = require("../textarea.cjs");
37
37
  const external_tooltip_cjs_namespaceObject = require("../tooltip.cjs");
38
+ const external_collapse_cjs_namespaceObject = require("./collapse.cjs");
38
39
  const DEFAULT_AI_ASSIST_ACTION_STRINGS = {
39
40
  trigger: 'AI assist',
40
41
  tooltip: 'Generate with AI',
@@ -84,14 +85,15 @@ function AiAssistAction({ onGenerate, hint, renderContent, disabled, strings })
84
85
  asChild: true,
85
86
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverTrigger, {
86
87
  asChild: true,
87
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
88
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_button_cjs_namespaceObject.Button, {
88
89
  type: "button",
90
+ variant: "ghost",
91
+ size: "3xs",
92
+ icon: true,
89
93
  "aria-label": text.trigger,
90
94
  disabled: disabled,
91
- className: "grid size-7 place-items-center rounded-lg text-foreground-subtle transition hover:bg-surface-overlay hover:text-foreground disabled:pointer-events-none disabled:opacity-50",
92
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Sparkles, {
93
- size: 12
94
- })
95
+ className: external_collapse_cjs_namespaceObject.FIELD_ACTION_CLASS,
96
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Sparkles, {})
95
97
  })
96
98
  })
97
99
  }),
@@ -6,6 +6,7 @@ import { Label } from "../label.js";
6
6
  import { Popover, PopoverContent, PopoverTrigger } from "../popover.js";
7
7
  import { Textarea } from "../textarea.js";
8
8
  import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip.js";
9
+ import { FIELD_ACTION_CLASS } from "./collapse.js";
9
10
  const DEFAULT_AI_ASSIST_ACTION_STRINGS = {
10
11
  trigger: 'AI assist',
11
12
  tooltip: 'Generate with AI',
@@ -55,14 +56,15 @@ function AiAssistAction({ onGenerate, hint, renderContent, disabled, strings })
55
56
  asChild: true,
56
57
  children: /*#__PURE__*/ jsx(PopoverTrigger, {
57
58
  asChild: true,
58
- children: /*#__PURE__*/ jsx("button", {
59
+ children: /*#__PURE__*/ jsx(Button, {
59
60
  type: "button",
61
+ variant: "ghost",
62
+ size: "3xs",
63
+ icon: true,
60
64
  "aria-label": text.trigger,
61
65
  disabled: disabled,
62
- className: "grid size-7 place-items-center rounded-lg text-foreground-subtle transition hover:bg-surface-overlay hover:text-foreground disabled:pointer-events-none disabled:opacity-50",
63
- children: /*#__PURE__*/ jsx(Sparkles, {
64
- size: 12
65
- })
66
+ className: FIELD_ACTION_CLASS,
67
+ children: /*#__PURE__*/ jsx(Sparkles, {})
66
68
  })
67
69
  })
68
70
  }),
@@ -25,19 +25,19 @@ var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
27
  COLLAPSED_HIDDEN: ()=>COLLAPSED_HIDDEN,
28
- COLLAPSED_ICON_PADDING: ()=>COLLAPSED_ICON_PADDING,
29
- COLLAPSED_ONLY: ()=>COLLAPSED_ONLY
28
+ COLLAPSED_ONLY: ()=>COLLAPSED_ONLY,
29
+ FIELD_ACTION_CLASS: ()=>FIELD_ACTION_CLASS
30
30
  });
31
31
  const COLLAPSED_HIDDEN = '@max-[259px]:hidden';
32
- const COLLAPSED_ICON_PADDING = '@max-[259px]:px-1.5';
33
- const COLLAPSED_ONLY = 'hidden @max-[259px]:block';
32
+ const COLLAPSED_ONLY = 'hidden @max-[259px]:flex';
33
+ const FIELD_ACTION_CLASS = 'text-muted-foreground hover:bg-accent hover:text-foreground [&_svg]:size-3';
34
34
  exports.COLLAPSED_HIDDEN = __webpack_exports__.COLLAPSED_HIDDEN;
35
- exports.COLLAPSED_ICON_PADDING = __webpack_exports__.COLLAPSED_ICON_PADDING;
36
35
  exports.COLLAPSED_ONLY = __webpack_exports__.COLLAPSED_ONLY;
36
+ exports.FIELD_ACTION_CLASS = __webpack_exports__.FIELD_ACTION_CLASS;
37
37
  for(var __rspack_i in __webpack_exports__)if (-1 === [
38
38
  "COLLAPSED_HIDDEN",
39
- "COLLAPSED_ICON_PADDING",
40
- "COLLAPSED_ONLY"
39
+ "COLLAPSED_ONLY",
40
+ "FIELD_ACTION_CLASS"
41
41
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
42
42
  Object.defineProperty(exports, '__esModule', {
43
43
  value: true
@@ -1,6 +1,9 @@
1
1
  /** Hidden once collapsed, such as an action's text. */
2
2
  export declare const COLLAPSED_HIDDEN = "@max-[259px]:hidden";
3
- /** The tighter padding of an action collapsed to its icon. */
4
- export declare const COLLAPSED_ICON_PADDING = "@max-[259px]:px-1.5";
5
3
  /** Shown only once collapsed. */
6
- export declare const COLLAPSED_ONLY = "hidden @max-[259px]:block";
4
+ export declare const COLLAPSED_ONLY = "hidden @max-[259px]:flex";
5
+ /**
6
+ * A header action is a ghost `3xs` Button, the height FormFieldHeader's `min-h-6` row expects, in
7
+ * the muted tone of the field's other icon buttons. Its icons are 12px.
8
+ */
9
+ export declare const FIELD_ACTION_CLASS = "text-muted-foreground hover:bg-accent hover:text-foreground [&_svg]:size-3";
@@ -1,4 +1,4 @@
1
1
  const COLLAPSED_HIDDEN = '@max-[259px]:hidden';
2
- const COLLAPSED_ICON_PADDING = '@max-[259px]:px-1.5';
3
- const COLLAPSED_ONLY = 'hidden @max-[259px]:block';
4
- export { COLLAPSED_HIDDEN, COLLAPSED_ICON_PADDING, COLLAPSED_ONLY };
2
+ const COLLAPSED_ONLY = 'hidden @max-[259px]:flex';
3
+ const FIELD_ACTION_CLASS = 'text-muted-foreground hover:bg-accent hover:text-foreground [&_svg]:size-3';
4
+ export { COLLAPSED_HIDDEN, COLLAPSED_ONLY, FIELD_ACTION_CLASS };