@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.
- package/dist/components/forms/metadata-form.cjs +3 -2
- package/dist/components/forms/metadata-form.js +3 -2
- package/dist/components/ui/editable-text.cjs +251 -0
- package/dist/components/ui/editable-text.d.ts +48 -0
- package/dist/components/ui/editable-text.js +217 -0
- package/dist/components/ui/field-actions/ai-assist-action.cjs +7 -5
- package/dist/components/ui/field-actions/ai-assist-action.js +7 -5
- package/dist/components/ui/field-actions/collapse.cjs +7 -7
- package/dist/components/ui/field-actions/collapse.d.ts +6 -3
- package/dist/components/ui/field-actions/collapse.js +3 -3
- package/dist/components/ui/field-actions/insert-variable-action.cjs +7 -7
- package/dist/components/ui/field-actions/insert-variable-action.js +8 -8
- package/dist/components/ui/field-addons/field-menu.cjs +2 -1
- package/dist/components/ui/field-addons/field-menu.d.ts +6 -1
- package/dist/components/ui/field-addons/field-menu.js +2 -1
- package/dist/components/ui/field-addons/value-mode-switch-dialog.cjs +2 -1
- package/dist/components/ui/field-addons/value-mode-switch-dialog.d.ts +6 -1
- package/dist/components/ui/field-addons/value-mode-switch-dialog.js +2 -1
- package/dist/components/ui/index.cjs +215 -202
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.js +1 -0
- package/dist/components/ui/input-group.cjs +7 -3
- package/dist/components/ui/input-group.d.ts +1 -1
- package/dist/components/ui/input-group.js +7 -3
- package/dist/components/ui/quick-form-field/components/field-header.cjs +55 -52
- package/dist/components/ui/quick-form-field/components/field-header.d.ts +13 -4
- package/dist/components/ui/quick-form-field/components/field-header.js +53 -53
- package/dist/components/ui/quick-form-field/index.d.ts +1 -1
- package/dist/components/ui/quick-form-field/quick-form-field.cjs +134 -17
- package/dist/components/ui/quick-form-field/quick-form-field.d.ts +6 -3
- package/dist/components/ui/quick-form-field/quick-form-field.js +136 -19
- package/dist/components/ui/quick-form-field/types.cjs +8 -0
- package/dist/components/ui/quick-form-field/types.d.ts +81 -14
- package/dist/components/ui/quick-form-field/types.js +8 -0
- package/dist/components/ui/quick-form-field/utils.cjs +30 -1
- package/dist/components/ui/quick-form-field/utils.d.ts +8 -0
- package/dist/components/ui/quick-form-field/utils.js +27 -1
- package/dist/components/ui/variable-value-control.cjs +7 -4
- package/dist/components/ui/variable-value-control.d.ts +5 -1
- package/dist/components/ui/variable-value-control.js +7 -4
- package/dist/index.cjs +4 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/styles.css +74 -22
- package/dist/tailwind.css +2 -1
- 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)("
|
|
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)("
|
|
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("
|
|
551
|
+
/*#__PURE__*/ jsx("h3", {
|
|
552
|
+
"data-slot": "form-section-header",
|
|
552
553
|
className: "flex",
|
|
553
|
-
children: /*#__PURE__*/ jsx("
|
|
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)(
|
|
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:
|
|
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(
|
|
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:
|
|
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
|
-
|
|
29
|
-
|
|
28
|
+
COLLAPSED_ONLY: ()=>COLLAPSED_ONLY,
|
|
29
|
+
FIELD_ACTION_CLASS: ()=>FIELD_ACTION_CLASS
|
|
30
30
|
});
|
|
31
31
|
const COLLAPSED_HIDDEN = '@max-[259px]:hidden';
|
|
32
|
-
const
|
|
33
|
-
const
|
|
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
|
-
"
|
|
40
|
-
"
|
|
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]:
|
|
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
|
|
3
|
-
const
|
|
4
|
-
export { COLLAPSED_HIDDEN,
|
|
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 };
|