@uipath/apollo-wind 2.79.2 → 2.80.1
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/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-addons/field-addon-button.cjs +36 -0
- package/dist/components/ui/field-addons/field-addon-button.d.ts +6 -0
- package/dist/components/ui/field-addons/field-addon-button.js +2 -0
- package/dist/components/ui/field-addons/field-menu.cjs +6 -6
- package/dist/components/ui/field-addons/field-menu.d.ts +6 -1
- package/dist/components/ui/field-addons/field-menu.js +6 -6
- 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 +220 -207
- 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 +41 -38
- 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 +38 -38
- package/dist/components/ui/quick-form-field/components/lock-toggle-button.cjs +2 -1
- package/dist/components/ui/quick-form-field/components/lock-toggle-button.js +2 -1
- 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 +69 -9
- package/package.json +1 -1
|
@@ -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 };
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
FIELD_ADDON_BUTTON_CLASS: ()=>FIELD_ADDON_BUTTON_CLASS
|
|
28
|
+
});
|
|
29
|
+
const FIELD_ADDON_BUTTON_CLASS = 'size-6 shrink-0 rounded-md p-0 text-muted-foreground hover:bg-accent hover:text-foreground';
|
|
30
|
+
exports.FIELD_ADDON_BUTTON_CLASS = __webpack_exports__.FIELD_ADDON_BUTTON_CLASS;
|
|
31
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
32
|
+
"FIELD_ADDON_BUTTON_CLASS"
|
|
33
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
34
|
+
Object.defineProperty(exports, '__esModule', {
|
|
35
|
+
value: true
|
|
36
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The square icon button an `InputGroupAddon` expects, on a 3xs InputGroupButton. Shared by
|
|
3
|
+
* FieldMenu's trigger and QuickFormField's lock toggle so both addon slots match, and not
|
|
4
|
+
* exported from the package.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FIELD_ADDON_BUTTON_CLASS = "size-6 shrink-0 rounded-md p-0 text-muted-foreground hover:bg-accent hover:text-foreground";
|
|
@@ -29,10 +29,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
29
29
|
});
|
|
30
30
|
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
31
31
|
const external_lucide_react_namespaceObject = require("lucide-react");
|
|
32
|
-
const external_button_cjs_namespaceObject = require("../button.cjs");
|
|
33
32
|
const external_dropdown_menu_cjs_namespaceObject = require("../dropdown-menu.cjs");
|
|
33
|
+
const external_input_group_cjs_namespaceObject = require("../input-group.cjs");
|
|
34
34
|
const index_cjs_namespaceObject = require("../../../lib/index.cjs");
|
|
35
35
|
const external_built_in_value_modes_cjs_namespaceObject = require("./built-in-value-modes.cjs");
|
|
36
|
+
const external_field_addon_button_cjs_namespaceObject = require("./field-addon-button.cjs");
|
|
36
37
|
const external_value_mode_strings_cjs_namespaceObject = require("./value-mode-strings.cjs");
|
|
37
38
|
const DEFAULT_MODES = [
|
|
38
39
|
'literal',
|
|
@@ -67,7 +68,7 @@ function ValueModeMenuItem({ icon: Icon, label, description, active, disabled, o
|
|
|
67
68
|
]
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
|
-
function FieldMenu({ mode, onSelect, modes, extraModes, actions, checked, modesDisabled, disabled, expectedType, literalDescription, triggerLabel: triggerLabelOverride, strings }) {
|
|
71
|
+
function FieldMenu({ mode, onSelect, modes, extraModes, actions, checked, modesDisabled, disabled, expectedType, literalDescription, triggerLabel: triggerLabelOverride, strings, onCloseAutoFocus }) {
|
|
71
72
|
const text = {
|
|
72
73
|
...external_value_mode_strings_cjs_namespaceObject.DEFAULT_VALUE_MODE_STRINGS,
|
|
73
74
|
...strings
|
|
@@ -90,19 +91,18 @@ function FieldMenu({ mode, onSelect, modes, extraModes, actions, checked, modesD
|
|
|
90
91
|
children: [
|
|
91
92
|
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_dropdown_menu_cjs_namespaceObject.DropdownMenuTrigger, {
|
|
92
93
|
asChild: true,
|
|
93
|
-
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(
|
|
94
|
-
type: "button",
|
|
95
|
-
variant: "ghost",
|
|
94
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupButton, {
|
|
96
95
|
size: "3xs",
|
|
97
96
|
disabled: disabled,
|
|
98
97
|
"aria-label": triggerLabel,
|
|
99
|
-
className:
|
|
98
|
+
className: external_field_addon_button_cjs_namespaceObject.FIELD_ADDON_BUTTON_CLASS,
|
|
100
99
|
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(TriggerIcon, {})
|
|
101
100
|
})
|
|
102
101
|
}),
|
|
103
102
|
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_dropdown_menu_cjs_namespaceObject.DropdownMenuContent, {
|
|
104
103
|
align: "end",
|
|
105
104
|
className: "w-56",
|
|
105
|
+
onCloseAutoFocus: onCloseAutoFocus,
|
|
106
106
|
children: [
|
|
107
107
|
!modesDisabled && resolvedModes.map((item)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(ValueModeMenuItem, {
|
|
108
108
|
icon: item.icon,
|
|
@@ -35,6 +35,11 @@ interface FieldMenuBaseProps<Id extends string> {
|
|
|
35
35
|
triggerLabel?: string;
|
|
36
36
|
/** Overrides for any subset of the English strings. */
|
|
37
37
|
strings?: Partial<ValueModeStrings>;
|
|
38
|
+
/**
|
|
39
|
+
* Called as the menu closes, before it returns focus to its trigger. Call `preventDefault` to keep
|
|
40
|
+
* focus elsewhere, such as on the field's control after a mode is chosen.
|
|
41
|
+
*/
|
|
42
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
38
43
|
}
|
|
39
44
|
/**
|
|
40
45
|
* `modes` may be omitted when `Id` is the built-in modes, or one of them as `mode="literal"` infers,
|
|
@@ -68,5 +73,5 @@ export declare function ValueModeMenuItem({ icon: Icon, label, description, acti
|
|
|
68
73
|
* shows the current mode's icon and is named by its title; with the modes hidden it is the field's
|
|
69
74
|
* overflow menu.
|
|
70
75
|
*/
|
|
71
|
-
export declare function FieldMenu<Id extends string = ValueMode>({ mode, onSelect, modes, extraModes, actions, checked, modesDisabled, disabled, expectedType, literalDescription, triggerLabel: triggerLabelOverride, strings, }: FieldMenuProps<Id>): import("react/jsx-runtime").JSX.Element;
|
|
76
|
+
export declare function FieldMenu<Id extends string = ValueMode>({ mode, onSelect, modes, extraModes, actions, checked, modesDisabled, disabled, expectedType, literalDescription, triggerLabel: triggerLabelOverride, strings, onCloseAutoFocus, }: FieldMenuProps<Id>): import("react/jsx-runtime").JSX.Element;
|
|
72
77
|
export {};
|