@mario_hahn/jumpy-ui 0.14.0 → 0.14.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/README.md +20 -0
- package/dist/chunk-KUCMD6DR.js +4304 -0
- package/dist/chunk-KYDYZC4E.js +365 -0
- package/dist/components.js +218 -0
- package/dist/editor.js +11 -0
- package/dist/index.js +80 -4549
- package/editor.d.ts +1 -0
- package/package.json +8 -2
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JumpField,
|
|
3
|
+
JumpyFieldContext
|
|
4
|
+
} from "./chunk-KUCMD6DR.js";
|
|
5
|
+
import {
|
|
6
|
+
JumpySpacing,
|
|
7
|
+
spacingValue,
|
|
8
|
+
useJumpyTheme
|
|
9
|
+
} from "./chunk-KDFNGI6Y.js";
|
|
10
|
+
|
|
11
|
+
// editor.js
|
|
12
|
+
import { useContext, useRef as useRef2, useState as useState2 } from "react";
|
|
13
|
+
|
|
14
|
+
// token-input.js
|
|
15
|
+
import { useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { $addUpdateTag, $createLineBreakNode, $createParagraphNode, $createTextNode, $getNodeByKey, $getRoot, $getSelection, $isElementNode, $isLineBreakNode, $isNodeSelection, $isRangeSelection, $isTextNode, $setSelection, CLEAR_HISTORY_COMMAND, COMMAND_PRIORITY_HIGH, COPY_COMMAND, CUT_COMMAND, DELETE_CHARACTER_COMMAND, DecoratorNode, HISTORY_PUSH_TAG, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, PASTE_COMMAND } from "lexical";
|
|
17
|
+
import { $generateJSONFromSelectedNodes } from "@lexical/clipboard";
|
|
18
|
+
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
19
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
20
|
+
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
21
|
+
import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin";
|
|
22
|
+
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
|
23
|
+
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
24
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
25
|
+
var clipboardType = "application/x-jumpy-token-input";
|
|
26
|
+
function normalizeTokenInputValue(value, multiline = false) {
|
|
27
|
+
const result = [];
|
|
28
|
+
const ids = /* @__PURE__ */ new Set();
|
|
29
|
+
for (const part of value) {
|
|
30
|
+
if (part.type === "text") {
|
|
31
|
+
const text = multiline ? part.text.replace(/\r\n?/g, "\n") : part.text.replace(/[\r\n]+/g, " ");
|
|
32
|
+
if (!text) continue;
|
|
33
|
+
const previous = result[result.length - 1];
|
|
34
|
+
if (previous?.type === "text") previous.text += text;
|
|
35
|
+
else result.push({ type: "text", text });
|
|
36
|
+
} else if (part.type === "token") {
|
|
37
|
+
if (typeof part.id !== "string" || !part.id || ids.has(part.id) || typeof part.value !== "string" || typeof part.label !== "string" || !part.label) throw new Error("JumpTokenInput tokens require unique ids, string values and non-empty labels");
|
|
38
|
+
ids.add(part.id);
|
|
39
|
+
result.push({ type: "token", id: part.id, value: part.value, label: part.label });
|
|
40
|
+
} else throw new Error("Unknown JumpTokenInput value part");
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function tokenInputText(value) {
|
|
45
|
+
return value.map((part) => part.type === "text" ? part.text : part.label).join("");
|
|
46
|
+
}
|
|
47
|
+
var JumpyTokenNode = class _JumpyTokenNode extends DecoratorNode {
|
|
48
|
+
static getType() {
|
|
49
|
+
return "jumpy-token";
|
|
50
|
+
}
|
|
51
|
+
static clone(node) {
|
|
52
|
+
return new _JumpyTokenNode(node.__token, node.__key);
|
|
53
|
+
}
|
|
54
|
+
static importJSON(json) {
|
|
55
|
+
return new _JumpyTokenNode(json.token);
|
|
56
|
+
}
|
|
57
|
+
constructor(token, key) {
|
|
58
|
+
super(key);
|
|
59
|
+
this.__token = { ...token };
|
|
60
|
+
}
|
|
61
|
+
exportJSON() {
|
|
62
|
+
return { ...super.exportJSON(), type: "jumpy-token", version: 1, token: { ...this.__token } };
|
|
63
|
+
}
|
|
64
|
+
getTextContent() {
|
|
65
|
+
return this.__token.label;
|
|
66
|
+
}
|
|
67
|
+
isInline() {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
isKeyboardSelectable() {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
createDOM() {
|
|
74
|
+
const element = document.createElement("span");
|
|
75
|
+
element.contentEditable = "false";
|
|
76
|
+
element.dataset.jumpyTokenId = this.__token.id;
|
|
77
|
+
element.style.display = "inline-block";
|
|
78
|
+
return element;
|
|
79
|
+
}
|
|
80
|
+
updateDOM() {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
decorate(editor) {
|
|
84
|
+
return /* @__PURE__ */ jsx(TokenChip, { editor, nodeKey: this.__key, token: this.__token });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function TokenChip({ editor, nodeKey, token }) {
|
|
88
|
+
const theme = useJumpyTheme();
|
|
89
|
+
const [editable, setEditable] = useState(editor.isEditable());
|
|
90
|
+
useEffect(() => editor.registerEditableListener(setEditable), [editor]);
|
|
91
|
+
return /* @__PURE__ */ jsxs("span", { "data-jumpy-slot": "input-token", style: { display: "inline-flex", maxWidth: "100%", boxSizing: "border-box", alignItems: "center", verticalAlign: "baseline", borderRadius: theme.radius.small, border: `${theme.borderWidth.small}px solid var(--jumpy-color-feedback-info-border)`, paddingInline: theme.spacing.small3XS, gap: theme.spacing.small3XS, background: "var(--jumpy-color-feedback-info-surface)", color: "var(--jumpy-color-text-primary)", fontSize: theme.fontFamily.bodySmall.fontSize, lineHeight: "inherit", whiteSpace: "inherit" }, children: [
|
|
92
|
+
/* @__PURE__ */ jsx("span", { style: { minWidth: 0 }, children: token.label }),
|
|
93
|
+
editable && /* @__PURE__ */ jsx("button", { type: "button", tabIndex: -1, "aria-label": `Remove ${token.label}`, onMouseDown: (event) => event.preventDefault(), onClick: (event) => {
|
|
94
|
+
event.preventDefault();
|
|
95
|
+
event.stopPropagation();
|
|
96
|
+
if (!editor.isEditable()) return;
|
|
97
|
+
editor.update(() => {
|
|
98
|
+
const node = $getNodeByKey(nodeKey);
|
|
99
|
+
if (node) {
|
|
100
|
+
node.selectPrevious();
|
|
101
|
+
node.remove();
|
|
102
|
+
}
|
|
103
|
+
}, { tag: HISTORY_PUSH_TAG });
|
|
104
|
+
editor.focus();
|
|
105
|
+
}, style: { display: "inline-flex", alignItems: "center", appearance: "none", border: 0, padding: 0, background: "transparent", color: "inherit", font: "inherit", cursor: "pointer" }, children: /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", focusable: "false", width: theme.fontFamily.bodySmall.fontSize, height: theme.fontFamily.bodySmall.fontSize, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "m4 4 8 8M12 4l-8 8", stroke: "currentColor", strokeWidth: "1.5" }) }) })
|
|
106
|
+
] });
|
|
107
|
+
}
|
|
108
|
+
function $readValue(multiline = false) {
|
|
109
|
+
const parts = [];
|
|
110
|
+
function visit(node) {
|
|
111
|
+
if (node instanceof JumpyTokenNode) parts.push({ ...node.__token });
|
|
112
|
+
else if ($isTextNode(node)) parts.push({ type: "text", text: node.getTextContent() });
|
|
113
|
+
else if ($isLineBreakNode(node)) parts.push({ type: "text", text: "\n" });
|
|
114
|
+
else if ($isElementNode(node)) node.getChildren().forEach(visit);
|
|
115
|
+
}
|
|
116
|
+
$getRoot().getChildren().forEach((node, index) => {
|
|
117
|
+
if (index > 0) parts.push({ type: "text", text: "\n" });
|
|
118
|
+
visit(node);
|
|
119
|
+
});
|
|
120
|
+
return normalizeTokenInputValue(parts, multiline);
|
|
121
|
+
}
|
|
122
|
+
function $nodes(parts) {
|
|
123
|
+
return parts.flatMap((part) => part.type === "token" ? [new JumpyTokenNode(part)] : part.text.split("\n").flatMap((text, index) => [
|
|
124
|
+
...index > 0 ? [$createLineBreakNode()] : [],
|
|
125
|
+
...text ? [$createTextNode(text)] : []
|
|
126
|
+
]));
|
|
127
|
+
}
|
|
128
|
+
function $replaceValue(parts) {
|
|
129
|
+
$getRoot().clear().append($createParagraphNode().append(...$nodes(parts)));
|
|
130
|
+
}
|
|
131
|
+
function $adjacentToken(backward) {
|
|
132
|
+
const selection = $getSelection();
|
|
133
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed()) return null;
|
|
134
|
+
const { offset, type } = selection.anchor;
|
|
135
|
+
const node = selection.anchor.getNode();
|
|
136
|
+
if (type === "element" && $isElementNode(node)) return node.getChildAtIndex(offset - (backward ? 1 : 0));
|
|
137
|
+
if ($isTextNode(node) && (backward ? offset === 0 : offset === node.getTextContentSize())) return backward ? node.getPreviousSibling() : node.getNextSibling();
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function EditorBehavior({ model, multiline, editable, editorRef, onValueChange, onChange, onClear }) {
|
|
141
|
+
const [editor] = useLexicalComposerContext();
|
|
142
|
+
const savedSelection = useRef(null);
|
|
143
|
+
const callbacks = useRef({ onValueChange, onChange, onClear });
|
|
144
|
+
callbacks.current = { onValueChange, onChange, onClear };
|
|
145
|
+
const previousMode = useRef(multiline);
|
|
146
|
+
useLayoutEffect(() => {
|
|
147
|
+
editor.setEditable(editable);
|
|
148
|
+
}, [editor, editable]);
|
|
149
|
+
useLayoutEffect(() => {
|
|
150
|
+
const current = editor.getEditorState().read(() => $readValue(multiline));
|
|
151
|
+
if (previousMode.current !== multiline || JSON.stringify(current) !== JSON.stringify(model)) {
|
|
152
|
+
savedSelection.current = null;
|
|
153
|
+
editor.update(() => {
|
|
154
|
+
$replaceValue(model);
|
|
155
|
+
$setSelection(null);
|
|
156
|
+
}, { tag: "jumpy-external-value" });
|
|
157
|
+
editor.dispatchCommand(CLEAR_HISTORY_COMMAND, void 0);
|
|
158
|
+
}
|
|
159
|
+
previousMode.current = multiline;
|
|
160
|
+
}, [editor, model, multiline]);
|
|
161
|
+
function insert(parts) {
|
|
162
|
+
if (!editor.isEditable()) return;
|
|
163
|
+
editor.update(() => {
|
|
164
|
+
const selection = savedSelection.current?.clone() || $getSelection();
|
|
165
|
+
if (selection) $setSelection(selection);
|
|
166
|
+
else $getRoot().selectEnd();
|
|
167
|
+
$getSelection()?.insertNodes($nodes(parts));
|
|
168
|
+
}, { tag: HISTORY_PUSH_TAG });
|
|
169
|
+
editor.focus();
|
|
170
|
+
}
|
|
171
|
+
useImperativeHandle(editorRef, () => ({
|
|
172
|
+
focus: () => editor.focus(),
|
|
173
|
+
insertText: (text) => insert(normalizeTokenInputValue([{ type: "text", text }], multiline)),
|
|
174
|
+
insertToken: (token) => {
|
|
175
|
+
const part = { ...token, type: "token", id: token.id || crypto.randomUUID() };
|
|
176
|
+
const current = editor.getEditorState().read(() => $readValue(multiline));
|
|
177
|
+
normalizeTokenInputValue([...current, part], multiline);
|
|
178
|
+
insert([part]);
|
|
179
|
+
},
|
|
180
|
+
removeToken: (id) => {
|
|
181
|
+
if (!editor.isEditable()) return;
|
|
182
|
+
editor.update(() => {
|
|
183
|
+
function remove(node) {
|
|
184
|
+
if (node instanceof JumpyTokenNode && node.__token.id === id) {
|
|
185
|
+
node.selectPrevious();
|
|
186
|
+
node.remove();
|
|
187
|
+
} else if ($isElementNode(node)) node.getChildren().forEach(remove);
|
|
188
|
+
}
|
|
189
|
+
remove($getRoot());
|
|
190
|
+
}, { tag: HISTORY_PUSH_TAG });
|
|
191
|
+
},
|
|
192
|
+
clear: () => {
|
|
193
|
+
if (!editor.isEditable()) return;
|
|
194
|
+
if (editor.getEditorState().read(() => $readValue(multiline).length) === 0) return;
|
|
195
|
+
editor.update(() => {
|
|
196
|
+
if (!$getSelection()) $getRoot().selectEnd();
|
|
197
|
+
}, { discrete: true });
|
|
198
|
+
editor.update(() => {
|
|
199
|
+
$replaceValue([]);
|
|
200
|
+
$getRoot().selectStart();
|
|
201
|
+
}, { tag: [HISTORY_PUSH_TAG, "jumpy-clear"] });
|
|
202
|
+
editor.focus();
|
|
203
|
+
}
|
|
204
|
+
}));
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
let previous = JSON.stringify(editor.getEditorState().read(() => $readValue(multiline)));
|
|
207
|
+
const unregisterUpdate = editor.registerUpdateListener(({ editorState, tags }) => {
|
|
208
|
+
editorState.read(() => {
|
|
209
|
+
const selection = $getSelection();
|
|
210
|
+
if (selection) savedSelection.current = selection.clone();
|
|
211
|
+
const next = $readValue(multiline);
|
|
212
|
+
const json = JSON.stringify(next);
|
|
213
|
+
if (json === previous) return;
|
|
214
|
+
previous = json;
|
|
215
|
+
if (tags.has("jumpy-external-value")) return;
|
|
216
|
+
callbacks.current.onChange?.({ target: { value: tokenInputText(next) }, currentTarget: { value: tokenInputText(next) } });
|
|
217
|
+
callbacks.current.onValueChange(next);
|
|
218
|
+
if (tags.has("jumpy-clear")) callbacks.current.onClear?.();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
const deleteToken = (event, backward) => {
|
|
222
|
+
if (!editor.isEditable() || editor.isComposing()) return false;
|
|
223
|
+
const selection = $getSelection();
|
|
224
|
+
if ($isNodeSelection(selection)) {
|
|
225
|
+
$addUpdateTag(HISTORY_PUSH_TAG);
|
|
226
|
+
event?.preventDefault();
|
|
227
|
+
for (const node2 of selection.getNodes()) {
|
|
228
|
+
node2.selectPrevious();
|
|
229
|
+
node2.remove();
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
const node = $adjacentToken(backward);
|
|
234
|
+
if (!(node instanceof JumpyTokenNode)) return false;
|
|
235
|
+
$addUpdateTag(HISTORY_PUSH_TAG);
|
|
236
|
+
event?.preventDefault();
|
|
237
|
+
node.selectPrevious();
|
|
238
|
+
node.remove();
|
|
239
|
+
return true;
|
|
240
|
+
};
|
|
241
|
+
const copy = (event, cut) => {
|
|
242
|
+
if (!event?.clipboardData || cut && !editor.isEditable()) return false;
|
|
243
|
+
const selection = $getSelection();
|
|
244
|
+
if (!selection || $isRangeSelection(selection) && selection.isCollapsed()) return false;
|
|
245
|
+
const { nodes } = $generateJSONFromSelectedNodes(editor, selection);
|
|
246
|
+
const parts = [];
|
|
247
|
+
const visit = (node) => {
|
|
248
|
+
if (node.type === "jumpy-token") parts.push(node.token);
|
|
249
|
+
else if (node.type === "text") parts.push({ type: "text", text: node.text });
|
|
250
|
+
else if (node.type === "linebreak") parts.push({ type: "text", text: "\n" });
|
|
251
|
+
else node.children?.forEach(visit);
|
|
252
|
+
};
|
|
253
|
+
nodes.forEach((node, index) => {
|
|
254
|
+
if (index > 0 && node.type === "paragraph") parts.push({ type: "text", text: "\n" });
|
|
255
|
+
visit(node);
|
|
256
|
+
});
|
|
257
|
+
event.preventDefault();
|
|
258
|
+
event.clipboardData.setData("text/plain", tokenInputText(parts));
|
|
259
|
+
event.clipboardData.setData(clipboardType, JSON.stringify(parts));
|
|
260
|
+
if (cut) {
|
|
261
|
+
$addUpdateTag(HISTORY_PUSH_TAG);
|
|
262
|
+
if ($isNodeSelection(selection)) for (const node of selection.getNodes()) node.remove();
|
|
263
|
+
else if ($isRangeSelection(selection)) selection.removeText();
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
};
|
|
267
|
+
const commands = [
|
|
268
|
+
editor.registerCommand(DELETE_CHARACTER_COMMAND, (backward) => deleteToken(null, backward), COMMAND_PRIORITY_HIGH),
|
|
269
|
+
editor.registerCommand(KEY_BACKSPACE_COMMAND, (event) => deleteToken(event, true), COMMAND_PRIORITY_HIGH),
|
|
270
|
+
editor.registerCommand(KEY_DELETE_COMMAND, (event) => deleteToken(event, false), COMMAND_PRIORITY_HIGH),
|
|
271
|
+
editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
272
|
+
if (editor.isComposing()) return false;
|
|
273
|
+
event?.preventDefault();
|
|
274
|
+
if (editable && multiline && !event?.metaKey && !event?.ctrlKey) {
|
|
275
|
+
const selection = $getSelection();
|
|
276
|
+
if ($isRangeSelection(selection)) {
|
|
277
|
+
$addUpdateTag(HISTORY_PUSH_TAG);
|
|
278
|
+
selection.insertLineBreak();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}, COMMAND_PRIORITY_HIGH),
|
|
283
|
+
editor.registerCommand(COPY_COMMAND, (event) => copy(event, false), COMMAND_PRIORITY_HIGH),
|
|
284
|
+
editor.registerCommand(CUT_COMMAND, (event) => copy(event, true), COMMAND_PRIORITY_HIGH),
|
|
285
|
+
editor.registerCommand(PASTE_COMMAND, (event) => {
|
|
286
|
+
if (!event?.clipboardData || !editor.isEditable()) return false;
|
|
287
|
+
event.preventDefault();
|
|
288
|
+
$addUpdateTag(HISTORY_PUSH_TAG);
|
|
289
|
+
let parts;
|
|
290
|
+
try {
|
|
291
|
+
parts = normalizeTokenInputValue(JSON.parse(event.clipboardData.getData(clipboardType)).map((part) => part.type === "token" ? { ...part, id: crypto.randomUUID() } : part), multiline);
|
|
292
|
+
} catch {
|
|
293
|
+
parts = normalizeTokenInputValue([{ type: "text", text: event.clipboardData.getData("text/plain") }], multiline);
|
|
294
|
+
}
|
|
295
|
+
$getSelection()?.insertNodes($nodes(parts));
|
|
296
|
+
return true;
|
|
297
|
+
}, COMMAND_PRIORITY_HIGH)
|
|
298
|
+
];
|
|
299
|
+
return () => {
|
|
300
|
+
unregisterUpdate();
|
|
301
|
+
commands.forEach((unregister) => unregister());
|
|
302
|
+
};
|
|
303
|
+
}, [editor, multiline, editable]);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
function TokenEditor({ model, multiline = false, minRows = 3, maxRows, editorRef, onValueChange, onChange, onClear, onFocus, onBlur, fieldContext, value: _value, placeholder, disabled, readOnly, style, ...props }) {
|
|
307
|
+
const theme = useJumpyTheme();
|
|
308
|
+
const initialConfig = useMemo(() => ({ namespace: "JumpyTokenInput", nodes: [JumpyTokenNode], editable: !disabled && !readOnly, onError: (error) => {
|
|
309
|
+
throw error;
|
|
310
|
+
}, editorState: () => $replaceValue(model) }), []);
|
|
311
|
+
const offset = fieldContext?.hasLabel ? spacingValue(theme, JumpySpacing.large) : 0;
|
|
312
|
+
const lineHeight = theme.fontFamily.bodyMedium.fontSize * theme.fontFamily.bodyMedium.lineHeight;
|
|
313
|
+
return /* @__PURE__ */ jsx(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: "100%", minWidth: 0, marginTop: offset }, children: [
|
|
314
|
+
/* @__PURE__ */ jsx(
|
|
315
|
+
PlainTextPlugin,
|
|
316
|
+
{
|
|
317
|
+
contentEditable: /* @__PURE__ */ jsx(ContentEditable, { ...props, onFocusCapture: (event) => {
|
|
318
|
+
props.onFocusCapture?.(event);
|
|
319
|
+
onFocus?.(event);
|
|
320
|
+
}, onBlurCapture: (event) => {
|
|
321
|
+
props.onBlurCapture?.(event);
|
|
322
|
+
onBlur?.(event);
|
|
323
|
+
}, "data-jumpy-component": "token-input", role: "textbox", "aria-multiline": multiline, "aria-readonly": readOnly || void 0, "aria-disabled": disabled || void 0, tabIndex: disabled ? -1 : 0, style: { width: "100%", minHeight: lineHeight * (multiline ? minRows : 1), maxHeight: multiline && maxRows !== void 0 ? lineHeight * maxRows : void 0, padding: 0, outline: 0, overflowX: "auto", overflowY: multiline ? "auto" : void 0, whiteSpace: multiline ? "pre-wrap" : "pre", overflowWrap: multiline ? "anywhere" : void 0, color: "var(--jumpy-cmp-base-input-value-color)", fontFamily: theme.fontFamily.familyBase, fontSize: theme.fontFamily.bodyMedium.fontSize, lineHeight: theme.fontFamily.bodyMedium.lineHeight, ...style } }),
|
|
324
|
+
placeholder: null,
|
|
325
|
+
ErrorBoundary: LexicalErrorBoundary
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
model.length === 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { position: "absolute", top: 0, left: 0, pointerEvents: "none", color: "var(--jumpy-cmp-base-input-placeholder-color)", fontSize: theme.fontFamily.bodyMedium.fontSize, lineHeight: theme.fontFamily.bodyMedium.lineHeight }, children: placeholder }),
|
|
329
|
+
/* @__PURE__ */ jsx(HistoryPlugin, {}),
|
|
330
|
+
/* @__PURE__ */ jsx(EditorBehavior, { model, multiline, editable: !disabled && !readOnly, editorRef, onValueChange, onChange, onClear })
|
|
331
|
+
] }) });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// editor.js
|
|
335
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
336
|
+
function TokenEditorField(props) {
|
|
337
|
+
const fieldContext = useContext(JumpyFieldContext);
|
|
338
|
+
return /* @__PURE__ */ jsx2(TokenEditor, { ...props, fieldContext });
|
|
339
|
+
}
|
|
340
|
+
function JumpTokenInput({ ref, value, defaultValue = [], onChange, onTokenInsert, onTokenRemove, multiline = false, minRows = 3, maxRows, hideClearIcon = false, onClear, label, hint, status = "regular", error = false, disabled = false, readOnly = false, className = "", ...props }) {
|
|
341
|
+
const editorHandle = useRef2(null);
|
|
342
|
+
const [internalValue, setInternalValue] = useState2(() => normalizeTokenInputValue(defaultValue, multiline));
|
|
343
|
+
const [, refresh] = useState2(0);
|
|
344
|
+
if (multiline && (!Number.isInteger(minRows) || minRows < 1 || maxRows !== void 0 && (!Number.isInteger(maxRows) || maxRows < minRows))) throw new Error("JumpTokenInput requires minRows >= 1 and maxRows >= minRows");
|
|
345
|
+
const model = normalizeTokenInputValue(value === void 0 ? internalValue : value, multiline);
|
|
346
|
+
const change = (next) => {
|
|
347
|
+
if (disabled || readOnly) return;
|
|
348
|
+
if (value === void 0) setInternalValue(next);
|
|
349
|
+
else refresh((revision) => revision + 1);
|
|
350
|
+
onChange?.(next);
|
|
351
|
+
const previousTokens = model.filter((part) => part.type === "token");
|
|
352
|
+
const nextTokens = next.filter((part) => part.type === "token");
|
|
353
|
+
for (const token of nextTokens) if (!previousTokens.some((previous) => previous.id === token.id)) onTokenInsert?.(token);
|
|
354
|
+
for (const token of previousTokens) if (!nextTokens.some((current) => current.id === token.id)) onTokenRemove?.(token);
|
|
355
|
+
};
|
|
356
|
+
return /* @__PURE__ */ jsx2(JumpField, { label, hint, status, error, hideClearIcon, onClear: () => editorHandle.current?.clear(), className, children: /* @__PURE__ */ jsx2(TokenEditorField, { ...props, "data-jumpy-token-editor": true, editorRef: (handle) => {
|
|
357
|
+
editorHandle.current = handle;
|
|
358
|
+
if (typeof ref === "function") return ref(handle);
|
|
359
|
+
if (ref) ref.current = handle;
|
|
360
|
+
}, model, multiline, minRows, maxRows, value: tokenInputText(model), "data-has-value": model.length > 0, disabled, readOnly, onValueChange: change, onClear }) });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export {
|
|
364
|
+
JumpTokenInput
|
|
365
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
BrandMark,
|
|
4
|
+
JumpAppShell,
|
|
5
|
+
JumpAvatar,
|
|
6
|
+
JumpBackground,
|
|
7
|
+
JumpBadge,
|
|
8
|
+
JumpBanner,
|
|
9
|
+
JumpBaseInput,
|
|
10
|
+
JumpButton,
|
|
11
|
+
JumpCard,
|
|
12
|
+
JumpCheckbox,
|
|
13
|
+
JumpChip,
|
|
14
|
+
JumpChoice,
|
|
15
|
+
JumpDatePicker,
|
|
16
|
+
JumpDialog,
|
|
17
|
+
JumpDivider,
|
|
18
|
+
JumpDropdown,
|
|
19
|
+
JumpExpandable,
|
|
20
|
+
JumpExpandableGroup,
|
|
21
|
+
JumpField,
|
|
22
|
+
JumpGrid,
|
|
23
|
+
JumpGridItem,
|
|
24
|
+
JumpHyperlink,
|
|
25
|
+
JumpIconButton,
|
|
26
|
+
JumpInput,
|
|
27
|
+
JumpLinkButton,
|
|
28
|
+
JumpList,
|
|
29
|
+
JumpListItem,
|
|
30
|
+
JumpLoader,
|
|
31
|
+
JumpMenu,
|
|
32
|
+
JumpMenuItem,
|
|
33
|
+
JumpModal,
|
|
34
|
+
JumpNotice,
|
|
35
|
+
JumpPageControl,
|
|
36
|
+
JumpPinInput,
|
|
37
|
+
JumpPopover,
|
|
38
|
+
JumpRadioGroup,
|
|
39
|
+
JumpSearchField,
|
|
40
|
+
JumpSectionFooter,
|
|
41
|
+
JumpSectionHeader,
|
|
42
|
+
JumpSheet,
|
|
43
|
+
JumpSideMenu,
|
|
44
|
+
JumpSideMenuItem,
|
|
45
|
+
JumpSkeletonLoader,
|
|
46
|
+
JumpSnackbarProvider,
|
|
47
|
+
JumpSpinner,
|
|
48
|
+
JumpSwitch,
|
|
49
|
+
JumpTabBar,
|
|
50
|
+
JumpTabBarItem,
|
|
51
|
+
JumpTable,
|
|
52
|
+
JumpTableBody,
|
|
53
|
+
JumpTableCell,
|
|
54
|
+
JumpTableFooter,
|
|
55
|
+
JumpTableHead,
|
|
56
|
+
JumpTableHeaderCell,
|
|
57
|
+
JumpTableRow,
|
|
58
|
+
JumpTabs,
|
|
59
|
+
JumpTag,
|
|
60
|
+
JumpTextarea,
|
|
61
|
+
JumpTimePicker,
|
|
62
|
+
JumpToggleButton,
|
|
63
|
+
JumpToggleButtonGroup,
|
|
64
|
+
JumpTooltip,
|
|
65
|
+
JumpTopBar,
|
|
66
|
+
JumpTypography,
|
|
67
|
+
KeyboardKeys,
|
|
68
|
+
applySubtreeSelection,
|
|
69
|
+
getHeaderCheckboxProps,
|
|
70
|
+
getNextSortOrder,
|
|
71
|
+
getRowCheckboxProps,
|
|
72
|
+
getSortActionLabel,
|
|
73
|
+
getSortMapping,
|
|
74
|
+
getSortOrder,
|
|
75
|
+
isRowFullySelected,
|
|
76
|
+
useJumpSnackbar
|
|
77
|
+
} from "./chunk-KUCMD6DR.js";
|
|
78
|
+
import {
|
|
79
|
+
JumpyAnimation,
|
|
80
|
+
JumpyAnimationDelay,
|
|
81
|
+
JumpyAnimationDuration,
|
|
82
|
+
JumpyBorderWidth,
|
|
83
|
+
JumpyOpacity,
|
|
84
|
+
JumpyRadius,
|
|
85
|
+
JumpyShadowStyle,
|
|
86
|
+
JumpySize,
|
|
87
|
+
JumpySpacing,
|
|
88
|
+
JumpyTextStyle,
|
|
89
|
+
JumpyThemeProvider,
|
|
90
|
+
animationDelayValue,
|
|
91
|
+
animationDurationValue,
|
|
92
|
+
animationEasingValue,
|
|
93
|
+
borderWidthValue,
|
|
94
|
+
createJumpyPresetFromAccent,
|
|
95
|
+
createJumpyTheme,
|
|
96
|
+
createJumpyThemeFromAccent,
|
|
97
|
+
createJumpyThemeFromPreset,
|
|
98
|
+
defaultJumpyTheme,
|
|
99
|
+
jumpyThemePresets,
|
|
100
|
+
opacityValue,
|
|
101
|
+
radiusValue,
|
|
102
|
+
shadowValue,
|
|
103
|
+
sizeValue,
|
|
104
|
+
spacingValue,
|
|
105
|
+
textStyleValue,
|
|
106
|
+
themeToCSSVariables,
|
|
107
|
+
useJumpyTheme
|
|
108
|
+
} from "./chunk-KDFNGI6Y.js";
|
|
109
|
+
import "./chunk-3DBKYKP2.js";
|
|
110
|
+
import {
|
|
111
|
+
jumpyThemeInventory
|
|
112
|
+
} from "./chunk-XDTVYUWG.js";
|
|
113
|
+
export {
|
|
114
|
+
BrandMark,
|
|
115
|
+
JumpAppShell,
|
|
116
|
+
JumpAvatar,
|
|
117
|
+
JumpBackground,
|
|
118
|
+
JumpBadge,
|
|
119
|
+
JumpBanner,
|
|
120
|
+
JumpBaseInput,
|
|
121
|
+
JumpButton,
|
|
122
|
+
JumpCard,
|
|
123
|
+
JumpCheckbox,
|
|
124
|
+
JumpChip,
|
|
125
|
+
JumpChoice,
|
|
126
|
+
JumpDatePicker,
|
|
127
|
+
JumpDialog,
|
|
128
|
+
JumpDivider,
|
|
129
|
+
JumpDropdown,
|
|
130
|
+
JumpExpandable,
|
|
131
|
+
JumpExpandableGroup,
|
|
132
|
+
JumpField,
|
|
133
|
+
JumpGrid,
|
|
134
|
+
JumpGridItem,
|
|
135
|
+
JumpHyperlink,
|
|
136
|
+
JumpIconButton,
|
|
137
|
+
JumpInput,
|
|
138
|
+
JumpLinkButton,
|
|
139
|
+
JumpList,
|
|
140
|
+
JumpListItem,
|
|
141
|
+
JumpLoader,
|
|
142
|
+
JumpMenu,
|
|
143
|
+
JumpMenuItem,
|
|
144
|
+
JumpModal,
|
|
145
|
+
JumpNotice,
|
|
146
|
+
JumpPageControl,
|
|
147
|
+
JumpPinInput,
|
|
148
|
+
JumpPopover,
|
|
149
|
+
JumpRadioGroup,
|
|
150
|
+
JumpSearchField,
|
|
151
|
+
JumpSectionFooter,
|
|
152
|
+
JumpSectionHeader,
|
|
153
|
+
JumpSheet,
|
|
154
|
+
JumpSideMenu,
|
|
155
|
+
JumpSideMenuItem,
|
|
156
|
+
JumpSkeletonLoader,
|
|
157
|
+
JumpSnackbarProvider,
|
|
158
|
+
JumpSpinner,
|
|
159
|
+
JumpSwitch,
|
|
160
|
+
JumpTabBar,
|
|
161
|
+
JumpTabBarItem,
|
|
162
|
+
JumpTable,
|
|
163
|
+
JumpTableBody,
|
|
164
|
+
JumpTableCell,
|
|
165
|
+
JumpTableFooter,
|
|
166
|
+
JumpTableHead,
|
|
167
|
+
JumpTableHeaderCell,
|
|
168
|
+
JumpTableRow,
|
|
169
|
+
JumpTabs,
|
|
170
|
+
JumpTag,
|
|
171
|
+
JumpTextarea,
|
|
172
|
+
JumpTimePicker,
|
|
173
|
+
JumpToggleButton,
|
|
174
|
+
JumpToggleButtonGroup,
|
|
175
|
+
JumpTooltip,
|
|
176
|
+
JumpTopBar,
|
|
177
|
+
JumpTypography,
|
|
178
|
+
JumpyAnimation,
|
|
179
|
+
JumpyAnimationDelay,
|
|
180
|
+
JumpyAnimationDuration,
|
|
181
|
+
JumpyBorderWidth,
|
|
182
|
+
JumpyOpacity,
|
|
183
|
+
JumpyRadius,
|
|
184
|
+
JumpyShadowStyle,
|
|
185
|
+
JumpySize,
|
|
186
|
+
JumpySpacing,
|
|
187
|
+
JumpyTextStyle,
|
|
188
|
+
JumpyThemeProvider,
|
|
189
|
+
KeyboardKeys,
|
|
190
|
+
animationDelayValue,
|
|
191
|
+
animationDurationValue,
|
|
192
|
+
animationEasingValue,
|
|
193
|
+
applySubtreeSelection,
|
|
194
|
+
borderWidthValue,
|
|
195
|
+
createJumpyPresetFromAccent,
|
|
196
|
+
createJumpyTheme,
|
|
197
|
+
createJumpyThemeFromAccent,
|
|
198
|
+
createJumpyThemeFromPreset,
|
|
199
|
+
defaultJumpyTheme,
|
|
200
|
+
getHeaderCheckboxProps,
|
|
201
|
+
getNextSortOrder,
|
|
202
|
+
getRowCheckboxProps,
|
|
203
|
+
getSortActionLabel,
|
|
204
|
+
getSortMapping,
|
|
205
|
+
getSortOrder,
|
|
206
|
+
isRowFullySelected,
|
|
207
|
+
jumpyThemeInventory,
|
|
208
|
+
jumpyThemePresets,
|
|
209
|
+
opacityValue,
|
|
210
|
+
radiusValue,
|
|
211
|
+
shadowValue,
|
|
212
|
+
sizeValue,
|
|
213
|
+
spacingValue,
|
|
214
|
+
textStyleValue,
|
|
215
|
+
themeToCSSVariables,
|
|
216
|
+
useJumpSnackbar,
|
|
217
|
+
useJumpyTheme
|
|
218
|
+
};
|
package/dist/editor.js
ADDED