@mario_hahn/jumpy-ui 0.14.0 → 0.14.2

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @mario_hahn/jumpy-ui
2
2
 
3
+ ## Editor bundle boundary (0.14.1)
4
+
5
+ Root imports remain compatible. `JumpTokenInput` is built in a separate chunk so
6
+ ordinary components/themes do not retain Lexical in Next.js Webpack/Turbopack
7
+ production initial scripts. Optional explicit import:
8
+
9
+ ```tsx
10
+ import { JumpTokenInput, type JumpTokenInputValue } from '@mario_hahn/jumpy-ui/editor'
11
+ ```
12
+
13
+ Both imports share the same theme/field contexts. CSS remains side-effectful.
14
+ Keep consumer workarounds for #5 until the fixed npm version is verified;
15
+ published 0.14.0 still has the defect.
16
+
3
17
  ## Button loading (0.10.0)
4
18
 
5
19
  `<JumpButton isLoading>Speichern</JumpButton>` keeps “Speichern” visible and adds a
@@ -369,6 +383,12 @@ import { JumpAppShell, JumpSideMenu, JumpSideMenuItem, JumpTabBar, JumpTabBarIte
369
383
 
370
384
  ## Token Packages
371
385
 
386
+ Native consumers can download the verified
387
+ [native-tokens-v0.14.0 release](https://github.com/mariohahn/jumpy-ui/releases/tag/native-tokens-v0.14.0)
388
+ instead of using npm or a full checkout. The release includes the archive,
389
+ SHA-256 and standalone installer. `NATIVE-TOKENS.md` in the repository documents
390
+ Xcode local-package and Gradle source-set integration.
391
+
372
392
  The npm package ships generated Web token artifacts under `tokens/web` (CSS, JS,
373
393
  and JSON per preset). Native artifacts are maintained in the repository, outside
374
394
  the npm distribution starting with 0.14.0.
@@ -15947,7 +15947,7 @@ var providerStyles = `
15947
15947
  Explicit columns so a hidden menu button does not shift the title. */
15948
15948
  [data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] {
15949
15949
  display: grid;
15950
- grid-template-columns: minmax(0, 1fr) minmax(0, max-content) minmax(0, 1fr);
15950
+ grid-template-columns: minmax(0, 1fr) minmax(0, max-content) minmax(max-content, 1fr);
15951
15951
  }
15952
15952
 
15953
15953
  [data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] > [data-jumpy-slot='top-bar-leading'] {
@@ -0,0 +1,365 @@
1
+ import {
2
+ JumpField,
3
+ JumpyFieldContext
4
+ } from "./chunk-SXBPGNRO.js";
5
+ import {
6
+ JumpySpacing,
7
+ spacingValue,
8
+ useJumpyTheme
9
+ } from "./chunk-2XOYK2JS.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
+ };