@jbpark/live-editor 2.0.0 → 2.0.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/dist/{ast-CrSMBsL4.js → ast-BKQmEBj9.js} +394 -71
- package/dist/ast-BKQmEBj9.js.map +1 -0
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/index.js +1 -1
- package/dist/{dnd-DMh9mSaU.js → dnd-Cyuif73L.js} +63 -180
- package/dist/dnd-Cyuif73L.js.map +1 -0
- package/dist/{index-7J3AYBNK.d.ts → index-2CUWhF-T.d.ts} +2 -2
- package/dist/{index-Wh6AGoXW.d.ts → index-FKgYmeNR.d.ts} +21 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/ast/index.d.ts +2 -2
- package/dist/utils/ast/index.js +2 -2
- package/package.json +1 -1
- package/dist/ast-CrSMBsL4.js.map +0 -1
- package/dist/dnd-DMh9mSaU.js.map +0 -1
|
@@ -426,6 +426,197 @@ const findEditableChildren = (node) => {
|
|
|
426
426
|
return editableChildren;
|
|
427
427
|
};
|
|
428
428
|
//#endregion
|
|
429
|
+
//#region src/utils/selection.ts
|
|
430
|
+
const removeIndices = (items, indices) => {
|
|
431
|
+
return items.filter((_, index) => !indices.has(index));
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* Shifts every selected index up/down by one step as a block, preserving
|
|
435
|
+
* relative order — scattered selections stop moving individually once they
|
|
436
|
+
* hit an unselected neighbor, so the whole group slides together instead of
|
|
437
|
+
* items passing through each other.
|
|
438
|
+
*/
|
|
439
|
+
const moveSelectedIndices = (items, indices, direction) => {
|
|
440
|
+
const next = [...items];
|
|
441
|
+
const nextIndices = new Set(indices);
|
|
442
|
+
const ordered = [...indices].sort((a, b) => direction === "up" ? a - b : b - a);
|
|
443
|
+
for (const index of ordered) {
|
|
444
|
+
const target = direction === "up" ? index - 1 : index + 1;
|
|
445
|
+
if (target < 0 || target >= next.length || nextIndices.has(target)) continue;
|
|
446
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
447
|
+
nextIndices.delete(index);
|
|
448
|
+
nextIndices.add(target);
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
items: next,
|
|
452
|
+
indices: nextIndices
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/utils/ast/tree.ts
|
|
457
|
+
const replaceIds = (code, generateId = () => nanoid(6)) => {
|
|
458
|
+
return code.replace(new RegExp(`${DATA_ATTR.ID}="[^"]*"`, "g"), () => {
|
|
459
|
+
return `${DATA_ATTR.ID}="${generateId()}"`;
|
|
460
|
+
});
|
|
461
|
+
};
|
|
462
|
+
const fillIds = (code, generateId = () => nanoid(6)) => {
|
|
463
|
+
return code.replace(new RegExp(`${DATA_ATTR.ID}=""`, "g"), () => {
|
|
464
|
+
return `${DATA_ATTR.ID}="${generateId()}"`;
|
|
465
|
+
});
|
|
466
|
+
};
|
|
467
|
+
const clone = (element, generateId = () => nanoid(6)) => {
|
|
468
|
+
const cloned = import_lib$2.cloneNode(element, true);
|
|
469
|
+
const generatedCode = generateCode(cloned);
|
|
470
|
+
const code = replaceIds(generatedCode, generateId);
|
|
471
|
+
return (0, import_lib$1.parseExpression)(code, { plugins: ["jsx", "typescript"] });
|
|
472
|
+
};
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/utils/ast/items.ts
|
|
475
|
+
const elementsOf = (code) => {
|
|
476
|
+
const ast = parseArrayExpression(code);
|
|
477
|
+
if (!ast) return null;
|
|
478
|
+
return ast.elements.filter((element) => Boolean(element));
|
|
479
|
+
};
|
|
480
|
+
const kindOf = (element) => import_lib$2.isObjectExpression(element) ? "object" : "primitive";
|
|
481
|
+
const toCode = (elements) => {
|
|
482
|
+
return generateCode(import_lib$2.arrayExpression(elements));
|
|
483
|
+
};
|
|
484
|
+
const parseItems = (code) => {
|
|
485
|
+
const elements = elementsOf(code);
|
|
486
|
+
if (!elements) return null;
|
|
487
|
+
return elements.map((node, index) => ({
|
|
488
|
+
index,
|
|
489
|
+
kind: kindOf(node),
|
|
490
|
+
node
|
|
491
|
+
}));
|
|
492
|
+
};
|
|
493
|
+
const resolveRenderLeaf = (render, key) => {
|
|
494
|
+
const leaf = render?.[key];
|
|
495
|
+
return leaf && "type" in leaf ? leaf : null;
|
|
496
|
+
};
|
|
497
|
+
const isLosslesslyEvaluable = (node) => {
|
|
498
|
+
if (import_lib$2.isStringLiteral(node) || import_lib$2.isNumericLiteral(node) || import_lib$2.isBooleanLiteral(node) || import_lib$2.isNullLiteral(node)) return true;
|
|
499
|
+
if (import_lib$2.isUnaryExpression(node) && node.operator === "-" && import_lib$2.isNumericLiteral(node.argument)) return true;
|
|
500
|
+
if (import_lib$2.isTemplateLiteral(node)) return node.expressions.length === 0;
|
|
501
|
+
if (import_lib$2.isArrayExpression(node)) return node.elements.every((element) => element !== null && isLosslesslyEvaluable(element));
|
|
502
|
+
if (import_lib$2.isObjectExpression(node)) return node.properties.every((property) => import_lib$2.isObjectProperty(property) && !property.computed && (import_lib$2.isIdentifier(property.key) || import_lib$2.isStringLiteral(property.key) || import_lib$2.isNumericLiteral(property.key)) && isLosslesslyEvaluable(property.value));
|
|
503
|
+
return false;
|
|
504
|
+
};
|
|
505
|
+
const toTemplateRaw = (value) => {
|
|
506
|
+
return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\r/g, "\\r");
|
|
507
|
+
};
|
|
508
|
+
const buildPropertyValue = (value, declaredType, renderLeaf, current) => {
|
|
509
|
+
if (renderLeaf?.property === BINDING_PROP.INNER_HTML) {
|
|
510
|
+
const raw = String(value);
|
|
511
|
+
return import_lib$2.templateLiteral([import_lib$2.templateElement({
|
|
512
|
+
raw: toTemplateRaw(raw),
|
|
513
|
+
cooked: raw
|
|
514
|
+
}, true)], []);
|
|
515
|
+
}
|
|
516
|
+
if (renderLeaf?.type === "jsx") {
|
|
517
|
+
const trimmed = String(value).trim();
|
|
518
|
+
if (!trimmed.startsWith("<")) return import_lib$2.stringLiteral(trimmed);
|
|
519
|
+
try {
|
|
520
|
+
return (0, import_lib$1.parseExpression)(trimmed, { plugins: ["jsx", "typescript"] });
|
|
521
|
+
} catch {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (declaredType === "array" || declaredType === "object") {
|
|
526
|
+
if (typeof value === "string") try {
|
|
527
|
+
return (0, import_lib$1.parseExpression)(value, { plugins: ["jsx", "typescript"] });
|
|
528
|
+
} catch {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (!isLosslesslyEvaluable(current)) return;
|
|
532
|
+
return valueToExpression(value) ?? void 0;
|
|
533
|
+
}
|
|
534
|
+
return createNodeFromValue(declaredType, parseValue(value)) ?? void 0;
|
|
535
|
+
};
|
|
536
|
+
const updateArrayItemProperty = (code, index, key, value, render) => {
|
|
537
|
+
const elements = elementsOf(code);
|
|
538
|
+
const element = elements?.[index];
|
|
539
|
+
if (!elements || !import_lib$2.isObjectExpression(element)) return null;
|
|
540
|
+
const target = element.properties.find((property) => import_lib$2.isObjectProperty(property) && import_lib$2.isIdentifier(property.key) && property.key.name === key);
|
|
541
|
+
if (!target) return null;
|
|
542
|
+
const declaredType = extractObjectProperties(element)[key]?.type ?? "string";
|
|
543
|
+
const nextValue = buildPropertyValue(value, declaredType, resolveRenderLeaf(render, key), target.value);
|
|
544
|
+
if (!nextValue) return null;
|
|
545
|
+
target.value = nextValue;
|
|
546
|
+
return toCode(elements);
|
|
547
|
+
};
|
|
548
|
+
const updateArrayItemValue = (code, index, value) => {
|
|
549
|
+
const elements = elementsOf(code);
|
|
550
|
+
const element = elements?.[index];
|
|
551
|
+
if (!elements || !element) return null;
|
|
552
|
+
const nextValue = createNodeFromValue(extractNodeValue(element).type, parseValue(value));
|
|
553
|
+
if (!nextValue) return null;
|
|
554
|
+
elements[index] = nextValue;
|
|
555
|
+
return toCode(elements);
|
|
556
|
+
};
|
|
557
|
+
const moveArrayItem = (code, from, to) => {
|
|
558
|
+
const elements = elementsOf(code);
|
|
559
|
+
if (!elements?.[from]) return null;
|
|
560
|
+
const next = [...elements];
|
|
561
|
+
const [moved] = next.splice(from, 1);
|
|
562
|
+
next.splice(to, 0, moved);
|
|
563
|
+
return toCode(next);
|
|
564
|
+
};
|
|
565
|
+
const moveArrayItems = (code, indices, direction) => {
|
|
566
|
+
const elements = elementsOf(code);
|
|
567
|
+
if (!elements) return null;
|
|
568
|
+
const { items, indices: nextIndices } = moveSelectedIndices(elements, indices, direction);
|
|
569
|
+
return {
|
|
570
|
+
code: toCode(items),
|
|
571
|
+
indices: nextIndices
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
const removeArrayItems = (code, indices, kind) => {
|
|
575
|
+
const elements = elementsOf(code);
|
|
576
|
+
if (!elements) return null;
|
|
577
|
+
const remaining = removeIndices(elements, indices);
|
|
578
|
+
if ((kind === void 0 ? remaining : remaining.filter((element) => kindOf(element) === kind)).length < 1) return null;
|
|
579
|
+
return toCode(remaining);
|
|
580
|
+
};
|
|
581
|
+
const cloneItem = (element, generateId) => {
|
|
582
|
+
const cloned = clone(element);
|
|
583
|
+
if (!import_lib$2.isObjectExpression(cloned)) return cloned;
|
|
584
|
+
const editable = extractObjectProperties(cloned);
|
|
585
|
+
cloned.properties.forEach((property) => {
|
|
586
|
+
if (!import_lib$2.isObjectProperty(property) || !import_lib$2.isIdentifier(property.key)) return;
|
|
587
|
+
const key = property.key.name;
|
|
588
|
+
if (key === "key" && import_lib$2.isStringLiteral(property.value)) {
|
|
589
|
+
property.value = import_lib$2.stringLiteral(`${property.value.value}-${generateId()}`);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const source = editable[key];
|
|
593
|
+
if (source) {
|
|
594
|
+
const next = createNodeFromValue(source.type, source.value);
|
|
595
|
+
if (next) property.value = next;
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
return cloned;
|
|
599
|
+
};
|
|
600
|
+
const duplicateArrayItems = (code, indices, generateId = () => nanoid(6)) => {
|
|
601
|
+
const elements = elementsOf(code);
|
|
602
|
+
if (!elements) return null;
|
|
603
|
+
const clones = [...indices].sort((a, b) => a - b).map((index) => elements[index]).filter((element) => Boolean(element)).map((element) => cloneItem(element, generateId));
|
|
604
|
+
if (clones.length === 0) return null;
|
|
605
|
+
return toCode([...elements, ...clones]);
|
|
606
|
+
};
|
|
607
|
+
const appendArrayItem = (code, kind, generateId = () => nanoid(6)) => {
|
|
608
|
+
const elements = elementsOf(code);
|
|
609
|
+
if (!elements) return null;
|
|
610
|
+
const template = elements.find((element) => kindOf(element) === kind);
|
|
611
|
+
if (!template) return null;
|
|
612
|
+
if (kind === "primitive") {
|
|
613
|
+
const { type, value } = extractNodeValue(template);
|
|
614
|
+
const next = createNodeFromValue(type, value);
|
|
615
|
+
return next ? toCode([...elements, next]) : null;
|
|
616
|
+
}
|
|
617
|
+
return toCode([...elements, cloneItem(template, generateId)]);
|
|
618
|
+
};
|
|
619
|
+
//#endregion
|
|
429
620
|
//#region src/utils/ast/extract.ts
|
|
430
621
|
const collectText = (children) => {
|
|
431
622
|
return children.filter((c) => import_lib$2.isJSXText(c)).map((c) => c.value.trim()).filter((v) => v.length).join(" ");
|
|
@@ -683,45 +874,196 @@ function clearExtractCache() {
|
|
|
683
874
|
extractCache.clear();
|
|
684
875
|
}
|
|
685
876
|
//#endregion
|
|
686
|
-
//#region src/utils/ast/
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
877
|
+
//#region src/utils/ast/patch.ts
|
|
878
|
+
const hasOnlyLayoutNewlines = (content) => {
|
|
879
|
+
let index = 0;
|
|
880
|
+
while (index < content.length) {
|
|
881
|
+
const char = content[index];
|
|
882
|
+
if (char === "`" || char === "<") return false;
|
|
883
|
+
if (char === "\"" || char === "'") {
|
|
884
|
+
const next = skipStringLiteral(content, index);
|
|
885
|
+
if (next === -1) return false;
|
|
886
|
+
index = next;
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
if (char === "/") {
|
|
890
|
+
const following = content[index + 1];
|
|
891
|
+
if (following === "/") {
|
|
892
|
+
const lineEnd = content.indexOf("\n", index + 2);
|
|
893
|
+
index = lineEnd === -1 ? content.length : lineEnd;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if (following === "*") {
|
|
897
|
+
const commentEnd = content.indexOf("*/", index + 2);
|
|
898
|
+
if (commentEnd === -1) return false;
|
|
899
|
+
index = commentEnd + 2;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
index++;
|
|
905
|
+
}
|
|
691
906
|
return true;
|
|
692
907
|
};
|
|
693
|
-
const
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
908
|
+
const skipStringLiteral = (content, start) => {
|
|
909
|
+
const quote = content[start];
|
|
910
|
+
for (let index = start + 1; index < content.length; index++) {
|
|
911
|
+
const char = content[index];
|
|
912
|
+
if (char === "\\") {
|
|
913
|
+
const escaped = content[index + 1];
|
|
914
|
+
if (escaped === "\n" || escaped === "\r") return -1;
|
|
915
|
+
index++;
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
if (char === quote) return index + 1;
|
|
919
|
+
if (char === "\n") return -1;
|
|
920
|
+
}
|
|
921
|
+
return -1;
|
|
698
922
|
};
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
return
|
|
923
|
+
const lineIndentAt = (source, offset) => {
|
|
924
|
+
const lineStart = source.lastIndexOf("\n", offset - 1) + 1;
|
|
925
|
+
return /^[ \t]*/.exec(source.slice(lineStart, offset))?.[0] ?? "";
|
|
702
926
|
};
|
|
703
|
-
const
|
|
927
|
+
const lineTerminatorOf = (source) => {
|
|
928
|
+
return source.includes("\r\n") ? "\r\n" : "\n";
|
|
929
|
+
};
|
|
930
|
+
const applyEdits = (source, edits) => {
|
|
931
|
+
if (edits.length === 0) return source;
|
|
932
|
+
const ordered = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
933
|
+
for (const edit of ordered) if (!Number.isInteger(edit.start) || !Number.isInteger(edit.end) || edit.start < 0 || edit.end > source.length || edit.start > edit.end) throw new Error(`Invalid source edit [${edit.start}, ${edit.end}) for a source of length ${source.length}`);
|
|
934
|
+
for (let i = 1; i < ordered.length; i++) {
|
|
935
|
+
const previous = ordered[i - 1];
|
|
936
|
+
const current = ordered[i];
|
|
937
|
+
if (current.start < previous.end) throw new Error(`Overlapping source edits: [${previous.start}, ${previous.end}) and [${current.start}, ${current.end})`);
|
|
938
|
+
}
|
|
939
|
+
let result = "";
|
|
940
|
+
let cursor = 0;
|
|
941
|
+
const terminator = lineTerminatorOf(source);
|
|
942
|
+
for (const edit of ordered) {
|
|
943
|
+
const content = edit.indent && edit.content.includes("\n") && hasOnlyLayoutNewlines(edit.content) ? edit.content.replace(/\n/g, `${terminator}${lineIndentAt(source, edit.start)}`) : edit.content;
|
|
944
|
+
result += source.slice(cursor, edit.start) + content;
|
|
945
|
+
cursor = edit.end;
|
|
946
|
+
}
|
|
947
|
+
return result + source.slice(cursor);
|
|
948
|
+
};
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/utils/ast/update.ts
|
|
951
|
+
const childrenRange = (element) => {
|
|
952
|
+
const { openingElement, closingElement } = element;
|
|
953
|
+
if (!closingElement || openingElement.end == null || closingElement.start == null) return null;
|
|
954
|
+
return {
|
|
955
|
+
start: openingElement.end,
|
|
956
|
+
end: closingElement.start
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
const findAttribute = (opening, propertyName) => {
|
|
960
|
+
return opening.attributes.find((attr) => import_lib$2.isJSXAttribute(attr) && import_lib$2.isJSXIdentifier(attr.name) && attr.name.name === propertyName);
|
|
961
|
+
};
|
|
962
|
+
const attributeInsertPoint = (opening) => {
|
|
963
|
+
return opening.attributes[opening.attributes.length - 1]?.end ?? opening.name.end ?? null;
|
|
964
|
+
};
|
|
965
|
+
const editInnerText = (source, element, value) => {
|
|
966
|
+
const range = childrenRange(element);
|
|
967
|
+
if (!range) return [];
|
|
968
|
+
const [only] = element.children;
|
|
969
|
+
if (element.children.length === 1 && import_lib$2.isJSXText(only) && only.start != null && only.end != null) {
|
|
970
|
+
const raw = source.slice(only.start, only.end);
|
|
971
|
+
if (raw.trim() !== "") {
|
|
972
|
+
const leading = raw.length - raw.trimStart().length;
|
|
973
|
+
const trailing = raw.length - raw.trimEnd().length;
|
|
974
|
+
return [{
|
|
975
|
+
start: only.start + leading,
|
|
976
|
+
end: only.end - trailing,
|
|
977
|
+
content: value
|
|
978
|
+
}];
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const edits = [];
|
|
982
|
+
for (const child of element.children) if (import_lib$2.isJSXText(child) && child.start != null && child.end != null) edits.push({
|
|
983
|
+
start: child.start,
|
|
984
|
+
end: child.end,
|
|
985
|
+
content: ""
|
|
986
|
+
});
|
|
987
|
+
edits.push({
|
|
988
|
+
start: range.end,
|
|
989
|
+
end: range.end,
|
|
990
|
+
content: value
|
|
991
|
+
});
|
|
992
|
+
return edits;
|
|
993
|
+
};
|
|
994
|
+
const editInnerHTML = (element, value) => {
|
|
995
|
+
const range = childrenRange(element);
|
|
996
|
+
if (!range) return [];
|
|
997
|
+
return [{
|
|
998
|
+
start: range.start,
|
|
999
|
+
end: range.end,
|
|
1000
|
+
content: value
|
|
1001
|
+
}];
|
|
1002
|
+
};
|
|
1003
|
+
const editChildren = (element, value) => {
|
|
704
1004
|
try {
|
|
705
1005
|
const childrenData = typeof value === "string" ? JSON.parse(value) : value;
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1006
|
+
const range = childrenRange(element);
|
|
1007
|
+
if (!range) return [];
|
|
1008
|
+
const content = childrenData.map((childData) => nodeToJSX(childData)).filter((node) => node !== null).map((node) => generateCode(node)).join("");
|
|
1009
|
+
return [{
|
|
1010
|
+
start: range.start,
|
|
1011
|
+
end: range.end,
|
|
1012
|
+
content,
|
|
1013
|
+
indent: true
|
|
1014
|
+
}];
|
|
712
1015
|
} catch (error) {
|
|
713
1016
|
console.error("❌ Children update error:", error);
|
|
714
|
-
return
|
|
1017
|
+
return null;
|
|
715
1018
|
}
|
|
716
1019
|
};
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1020
|
+
const editRichtext = (element, value) => {
|
|
1021
|
+
const edits = [];
|
|
1022
|
+
const range = childrenRange(element);
|
|
1023
|
+
if (range && range.start !== range.end) edits.push({
|
|
1024
|
+
start: range.start,
|
|
1025
|
+
end: range.end,
|
|
1026
|
+
content: ""
|
|
1027
|
+
});
|
|
1028
|
+
const opening = element.openingElement;
|
|
1029
|
+
const attribute = import_lib$2.jsxAttribute(import_lib$2.jsxIdentifier("dangerouslySetInnerHTML"), import_lib$2.jsxExpressionContainer(import_lib$2.objectExpression([import_lib$2.objectProperty(import_lib$2.identifier("__html"), import_lib$2.stringLiteral(value))])));
|
|
1030
|
+
const content = generateCode(attribute);
|
|
1031
|
+
const existing = findAttribute(opening, "dangerouslySetInnerHTML");
|
|
1032
|
+
if (existing && existing.start != null && existing.end != null) {
|
|
1033
|
+
edits.push({
|
|
1034
|
+
start: existing.start,
|
|
1035
|
+
end: existing.end,
|
|
1036
|
+
content,
|
|
1037
|
+
indent: true
|
|
1038
|
+
});
|
|
1039
|
+
return edits;
|
|
1040
|
+
}
|
|
1041
|
+
const insertAt = attributeInsertPoint(opening);
|
|
1042
|
+
if (insertAt == null) return null;
|
|
1043
|
+
edits.push({
|
|
1044
|
+
start: insertAt,
|
|
1045
|
+
end: insertAt,
|
|
1046
|
+
content: ` ${content}`,
|
|
1047
|
+
indent: true
|
|
1048
|
+
});
|
|
1049
|
+
return edits;
|
|
1050
|
+
};
|
|
1051
|
+
const editJsxAttribute = (opening, propertyName, value) => {
|
|
1052
|
+
const attribute = findAttribute(opening, propertyName);
|
|
1053
|
+
if (!attribute) return null;
|
|
1054
|
+
const content = `{${String(value).trim()}}`;
|
|
1055
|
+
if (attribute.value?.start != null && attribute.value.end != null) return [{
|
|
1056
|
+
start: attribute.value.start,
|
|
1057
|
+
end: attribute.value.end,
|
|
1058
|
+
content
|
|
1059
|
+
}];
|
|
1060
|
+
const insertAt = attribute.name.end;
|
|
1061
|
+
if (insertAt == null) return null;
|
|
1062
|
+
return [{
|
|
1063
|
+
start: insertAt,
|
|
1064
|
+
end: insertAt,
|
|
1065
|
+
content: `=${content}`
|
|
1066
|
+
}];
|
|
725
1067
|
};
|
|
726
1068
|
const buildAttributeValue = (value, type) => {
|
|
727
1069
|
if (type === "array" || type === "object") {
|
|
@@ -737,13 +1079,16 @@ const buildAttributeValue = (value, type) => {
|
|
|
737
1079
|
const expr = valueToExpression(value);
|
|
738
1080
|
return expr ? import_lib$2.jsxExpressionContainer(expr) : import_lib$2.stringLiteral(String(value));
|
|
739
1081
|
};
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
if (
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
1082
|
+
const editAttribute = (opening, propertyName, value, type) => {
|
|
1083
|
+
const attribute = findAttribute(opening, propertyName);
|
|
1084
|
+
if (!attribute || attribute.start == null || attribute.end == null) return null;
|
|
1085
|
+
const content = generateCode(import_lib$2.jsxAttribute(attribute.name, buildAttributeValue(value, type)));
|
|
1086
|
+
return [{
|
|
1087
|
+
start: attribute.start,
|
|
1088
|
+
end: attribute.end,
|
|
1089
|
+
content,
|
|
1090
|
+
indent: true
|
|
1091
|
+
}];
|
|
747
1092
|
};
|
|
748
1093
|
const update = (code, dataId, label, value, property) => {
|
|
749
1094
|
try {
|
|
@@ -753,7 +1098,12 @@ const update = (code, dataId, label, value, property) => {
|
|
|
753
1098
|
plugins: ["jsx", "typescript"]
|
|
754
1099
|
});
|
|
755
1100
|
let changed = false;
|
|
756
|
-
const
|
|
1101
|
+
const edits = [];
|
|
1102
|
+
const collect = (result) => {
|
|
1103
|
+
if (!result) return;
|
|
1104
|
+
edits.push(...result);
|
|
1105
|
+
changed = true;
|
|
1106
|
+
};
|
|
757
1107
|
traverse(ast, { JSXElement(path) {
|
|
758
1108
|
const opening = path.node.openingElement;
|
|
759
1109
|
if (!opening.attributes.find((attr) => {
|
|
@@ -773,32 +1123,23 @@ const update = (code, dataId, label, value, property) => {
|
|
|
773
1123
|
const propertyBinding = matches[0];
|
|
774
1124
|
switch (propertyBinding.property) {
|
|
775
1125
|
case BINDING_PROP.INNER_TEXT:
|
|
776
|
-
|
|
1126
|
+
collect(editInnerText(wrapped, path.node, String(value)));
|
|
777
1127
|
break;
|
|
778
1128
|
case BINDING_PROP.INNER_HTML:
|
|
779
|
-
|
|
780
|
-
else changed = updateInnerHTML(path, String(value), jsxPlaceholders);
|
|
1129
|
+
collect(propertyBinding.type === "richtext" ? editRichtext(path.node, String(value)) : editInnerHTML(path.node, String(value)));
|
|
781
1130
|
break;
|
|
782
1131
|
case BINDING_PROP.CHILDREN:
|
|
783
|
-
|
|
1132
|
+
collect(editChildren(path.node, value));
|
|
784
1133
|
break;
|
|
785
|
-
default:
|
|
786
|
-
const attr = opening.attributes.find((a) => import_lib$2.isJSXAttribute(a) && import_lib$2.isJSXIdentifier(a.name) && a.name.name === propertyBinding.property);
|
|
787
|
-
if (attr && import_lib$2.isJSXAttribute(attr)) {
|
|
788
|
-
attr.value = injectPlaceholder("JSX", String(value).trim(), jsxPlaceholders);
|
|
789
|
-
changed = true;
|
|
790
|
-
}
|
|
791
|
-
} else changed = updateAttribute(opening, propertyBinding.property, value, propertyBinding.type);
|
|
1134
|
+
default: collect(propertyBinding.type === "jsx" ? editJsxAttribute(opening, propertyBinding.property, value) : editAttribute(opening, propertyBinding.property, value, propertyBinding.type));
|
|
792
1135
|
}
|
|
793
1136
|
} });
|
|
794
1137
|
if (!changed) return {
|
|
795
1138
|
code,
|
|
796
1139
|
success: false
|
|
797
1140
|
};
|
|
798
|
-
let result = unwrap(generateCode(ast));
|
|
799
|
-
for (const [placeholder, original] of jsxPlaceholders) result = result.replace(placeholder, () => original);
|
|
800
1141
|
return {
|
|
801
|
-
code:
|
|
1142
|
+
code: unwrap(applyEdits(wrapped, edits)),
|
|
802
1143
|
success: true
|
|
803
1144
|
};
|
|
804
1145
|
} catch (error) {
|
|
@@ -823,24 +1164,6 @@ const bulkUpdate = (raw, entries) => {
|
|
|
823
1164
|
};
|
|
824
1165
|
};
|
|
825
1166
|
//#endregion
|
|
826
|
-
//#region src/utils/ast/tree.ts
|
|
827
|
-
const replaceIds = (code, generateId = () => nanoid(6)) => {
|
|
828
|
-
return code.replace(new RegExp(`${DATA_ATTR.ID}="[^"]*"`, "g"), () => {
|
|
829
|
-
return `${DATA_ATTR.ID}="${generateId()}"`;
|
|
830
|
-
});
|
|
831
|
-
};
|
|
832
|
-
const fillIds = (code, generateId = () => nanoid(6)) => {
|
|
833
|
-
return code.replace(new RegExp(`${DATA_ATTR.ID}=""`, "g"), () => {
|
|
834
|
-
return `${DATA_ATTR.ID}="${generateId()}"`;
|
|
835
|
-
});
|
|
836
|
-
};
|
|
837
|
-
const clone = (element, generateId = () => nanoid(6)) => {
|
|
838
|
-
const cloned = import_lib$2.cloneNode(element, true);
|
|
839
|
-
const generatedCode = generateCode(cloned);
|
|
840
|
-
const code = replaceIds(generatedCode, generateId);
|
|
841
|
-
return (0, import_lib$1.parseExpression)(code, { plugins: ["jsx", "typescript"] });
|
|
842
|
-
};
|
|
843
|
-
//#endregion
|
|
844
1167
|
//#region src/utils/ast/validate.ts
|
|
845
1168
|
const VALID = { valid: true };
|
|
846
1169
|
const validateBindingValue = (binding, value) => {
|
|
@@ -890,6 +1213,6 @@ const validateBindingValue = (binding, value) => {
|
|
|
890
1213
|
return VALID;
|
|
891
1214
|
};
|
|
892
1215
|
//#endregion
|
|
893
|
-
export { generateCode as S,
|
|
1216
|
+
export { parseValue as A, parseBindingExpression as C, extractObjectProperties as D, extractNodeValue as E, generateCode as M, flattenEditableValue as O, parseBinding as S, createNodeFromValue as T, moveSelectedIndices as _, extract as a, getCurrentValue as b, moveArrayItem as c, removeArrayItems as d, updateArrayItemProperty as f, replaceIds as g, fillIds as h, clearExtractCache as i, setEditableValue as j, parseArrayExpression as k, moveArrayItems as l, clone as m, bulkUpdate as n, appendArrayItem as o, updateArrayItemValue as p, update as r, duplicateArrayItems as s, validateBindingValue as t, parseItems as u, removeIndices as v, arrayExpressionToCode as w, getStructuredValue as x, findEditableChildren as y };
|
|
894
1217
|
|
|
895
|
-
//# sourceMappingURL=ast-
|
|
1218
|
+
//# sourceMappingURL=ast-BKQmEBj9.js.map
|