@particle-academy/fancy-code 0.3.1 → 0.4.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 +3 -1
- package/dist/index.cjs +403 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +403 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -108,10 +108,11 @@ function CodeEditorPanel({ className }) {
|
|
|
108
108
|
"textarea",
|
|
109
109
|
{
|
|
110
110
|
ref: textareaRef,
|
|
111
|
-
className: "relative m-0 block w-full resize-none
|
|
111
|
+
className: "relative m-0 block w-full resize-none border-none bg-transparent p-2.5 text-[13px] leading-[1.5] text-transparent outline-none",
|
|
112
112
|
style: {
|
|
113
113
|
caretColor: themeColors.cursorColor,
|
|
114
114
|
minHeight: _minHeight ? _minHeight - 40 : 80,
|
|
115
|
+
overflow: "hidden",
|
|
115
116
|
whiteSpace: wordWrap ? "pre-wrap" : "pre",
|
|
116
117
|
overflowWrap: wordWrap ? "break-word" : "normal"
|
|
117
118
|
},
|
|
@@ -660,6 +661,377 @@ var tokenizePhp = (source) => {
|
|
|
660
661
|
return tokens;
|
|
661
662
|
};
|
|
662
663
|
|
|
664
|
+
// src/engine/tokenizers/python.ts
|
|
665
|
+
var KEYWORDS2 = /* @__PURE__ */ new Set([
|
|
666
|
+
"and",
|
|
667
|
+
"as",
|
|
668
|
+
"assert",
|
|
669
|
+
"async",
|
|
670
|
+
"await",
|
|
671
|
+
"break",
|
|
672
|
+
"class",
|
|
673
|
+
"continue",
|
|
674
|
+
"def",
|
|
675
|
+
"del",
|
|
676
|
+
"elif",
|
|
677
|
+
"else",
|
|
678
|
+
"except",
|
|
679
|
+
"finally",
|
|
680
|
+
"for",
|
|
681
|
+
"from",
|
|
682
|
+
"global",
|
|
683
|
+
"if",
|
|
684
|
+
"import",
|
|
685
|
+
"in",
|
|
686
|
+
"is",
|
|
687
|
+
"lambda",
|
|
688
|
+
"nonlocal",
|
|
689
|
+
"not",
|
|
690
|
+
"or",
|
|
691
|
+
"pass",
|
|
692
|
+
"raise",
|
|
693
|
+
"return",
|
|
694
|
+
"try",
|
|
695
|
+
"while",
|
|
696
|
+
"with",
|
|
697
|
+
"yield",
|
|
698
|
+
"True",
|
|
699
|
+
"False",
|
|
700
|
+
"None"
|
|
701
|
+
]);
|
|
702
|
+
var TYPES = /* @__PURE__ */ new Set([
|
|
703
|
+
"int",
|
|
704
|
+
"str",
|
|
705
|
+
"float",
|
|
706
|
+
"bool",
|
|
707
|
+
"list",
|
|
708
|
+
"dict",
|
|
709
|
+
"tuple",
|
|
710
|
+
"set",
|
|
711
|
+
"bytes",
|
|
712
|
+
"bytearray",
|
|
713
|
+
"memoryview",
|
|
714
|
+
"range",
|
|
715
|
+
"frozenset",
|
|
716
|
+
"complex",
|
|
717
|
+
"type",
|
|
718
|
+
"object",
|
|
719
|
+
"property",
|
|
720
|
+
"classmethod",
|
|
721
|
+
"staticmethod",
|
|
722
|
+
"Any",
|
|
723
|
+
"Optional",
|
|
724
|
+
"Union",
|
|
725
|
+
"Callable",
|
|
726
|
+
"List",
|
|
727
|
+
"Dict",
|
|
728
|
+
"Tuple",
|
|
729
|
+
"Set",
|
|
730
|
+
"Sequence",
|
|
731
|
+
"Mapping",
|
|
732
|
+
"Iterator",
|
|
733
|
+
"Generator",
|
|
734
|
+
"Coroutine"
|
|
735
|
+
]);
|
|
736
|
+
var tokenizePython = (source) => {
|
|
737
|
+
const tokens = [];
|
|
738
|
+
const len = source.length;
|
|
739
|
+
let i = 0;
|
|
740
|
+
while (i < len) {
|
|
741
|
+
const ch = source[i];
|
|
742
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
743
|
+
i++;
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (ch === "#") {
|
|
747
|
+
const pos = i;
|
|
748
|
+
i++;
|
|
749
|
+
while (i < len && source[i] !== "\n") i++;
|
|
750
|
+
tokens.push({ type: "comment", start: pos, end: i });
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
if (ch === "@" && i + 1 < len && /[a-zA-Z_]/.test(source[i + 1])) {
|
|
754
|
+
const pos = i;
|
|
755
|
+
i++;
|
|
756
|
+
while (i < len && /[a-zA-Z0-9_.]/.test(source[i])) i++;
|
|
757
|
+
tokens.push({ type: "keyword", start: pos, end: i });
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
if (ch === '"' || ch === "'" || (ch === "f" || ch === "r" || ch === "b" || ch === "F" || ch === "R" || ch === "B") && (source[i + 1] === '"' || source[i + 1] === "'")) {
|
|
761
|
+
const pos = i;
|
|
762
|
+
if (ch !== '"' && ch !== "'") i++;
|
|
763
|
+
const quote = source[i];
|
|
764
|
+
if (source[i + 1] === quote && source[i + 2] === quote) {
|
|
765
|
+
const triple = quote + quote + quote;
|
|
766
|
+
i += 3;
|
|
767
|
+
while (i < len && source.slice(i, i + 3) !== triple) {
|
|
768
|
+
if (source[i] === "\\") i++;
|
|
769
|
+
i++;
|
|
770
|
+
}
|
|
771
|
+
i += 3;
|
|
772
|
+
tokens.push({ type: "string", start: pos, end: i });
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
i++;
|
|
776
|
+
while (i < len && source[i] !== quote && source[i] !== "\n") {
|
|
777
|
+
if (source[i] === "\\") i++;
|
|
778
|
+
i++;
|
|
779
|
+
}
|
|
780
|
+
if (i < len && source[i] === quote) i++;
|
|
781
|
+
tokens.push({ type: "string", start: pos, end: i });
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
if (ch >= "0" && ch <= "9" || ch === "." && i + 1 < len && source[i + 1] >= "0" && source[i + 1] <= "9") {
|
|
785
|
+
const pos = i;
|
|
786
|
+
if (ch === "0" && (source[i + 1] === "x" || source[i + 1] === "X")) {
|
|
787
|
+
i += 2;
|
|
788
|
+
while (i < len && /[0-9a-fA-F_]/.test(source[i])) i++;
|
|
789
|
+
} else if (ch === "0" && (source[i + 1] === "b" || source[i + 1] === "B")) {
|
|
790
|
+
i += 2;
|
|
791
|
+
while (i < len && /[01_]/.test(source[i])) i++;
|
|
792
|
+
} else if (ch === "0" && (source[i + 1] === "o" || source[i + 1] === "O")) {
|
|
793
|
+
i += 2;
|
|
794
|
+
while (i < len && /[0-7_]/.test(source[i])) i++;
|
|
795
|
+
} else {
|
|
796
|
+
while (i < len && /[0-9_.]/.test(source[i])) i++;
|
|
797
|
+
if (i < len && (source[i] === "e" || source[i] === "E")) {
|
|
798
|
+
i++;
|
|
799
|
+
if (i < len && (source[i] === "+" || source[i] === "-")) i++;
|
|
800
|
+
while (i < len && source[i] >= "0" && source[i] <= "9") i++;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (i < len && source[i] === "j") i++;
|
|
804
|
+
tokens.push({ type: "number", start: pos, end: i });
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
if (/[a-zA-Z_]/.test(ch)) {
|
|
808
|
+
const pos = i;
|
|
809
|
+
i++;
|
|
810
|
+
while (i < len && /[a-zA-Z0-9_]/.test(source[i])) i++;
|
|
811
|
+
const word = source.slice(pos, i);
|
|
812
|
+
let j = i;
|
|
813
|
+
while (j < len && (source[j] === " " || source[j] === " ")) j++;
|
|
814
|
+
if (KEYWORDS2.has(word)) {
|
|
815
|
+
tokens.push({ type: "keyword", start: pos, end: i });
|
|
816
|
+
} else if (TYPES.has(word)) {
|
|
817
|
+
tokens.push({ type: "type", start: pos, end: i });
|
|
818
|
+
} else if (source[j] === "(") {
|
|
819
|
+
tokens.push({ type: "function", start: pos, end: i });
|
|
820
|
+
} else if (word[0] >= "A" && word[0] <= "Z") {
|
|
821
|
+
tokens.push({ type: "type", start: pos, end: i });
|
|
822
|
+
} else {
|
|
823
|
+
tokens.push({ type: "variable", start: pos, end: i });
|
|
824
|
+
}
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
if ("+-*/%=<>!&|^~:@".includes(ch)) {
|
|
828
|
+
const pos = i;
|
|
829
|
+
i++;
|
|
830
|
+
while (i < len && "+-*/%=<>!&|^~:".includes(source[i])) i++;
|
|
831
|
+
tokens.push({ type: "operator", start: pos, end: i });
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
if ("()[]{},.;\\".includes(ch)) {
|
|
835
|
+
tokens.push({ type: "punctuation", start: i, end: i + 1 });
|
|
836
|
+
i++;
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
tokens.push({ type: "plain", start: i, end: i + 1 });
|
|
840
|
+
i++;
|
|
841
|
+
}
|
|
842
|
+
return tokens;
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/engine/tokenizers/go.ts
|
|
846
|
+
var KEYWORDS3 = /* @__PURE__ */ new Set([
|
|
847
|
+
"break",
|
|
848
|
+
"case",
|
|
849
|
+
"chan",
|
|
850
|
+
"const",
|
|
851
|
+
"continue",
|
|
852
|
+
"default",
|
|
853
|
+
"defer",
|
|
854
|
+
"else",
|
|
855
|
+
"fallthrough",
|
|
856
|
+
"for",
|
|
857
|
+
"func",
|
|
858
|
+
"go",
|
|
859
|
+
"goto",
|
|
860
|
+
"if",
|
|
861
|
+
"import",
|
|
862
|
+
"interface",
|
|
863
|
+
"map",
|
|
864
|
+
"package",
|
|
865
|
+
"range",
|
|
866
|
+
"return",
|
|
867
|
+
"select",
|
|
868
|
+
"struct",
|
|
869
|
+
"switch",
|
|
870
|
+
"type",
|
|
871
|
+
"var",
|
|
872
|
+
"nil",
|
|
873
|
+
"true",
|
|
874
|
+
"false",
|
|
875
|
+
"iota"
|
|
876
|
+
]);
|
|
877
|
+
var TYPES2 = /* @__PURE__ */ new Set([
|
|
878
|
+
"bool",
|
|
879
|
+
"byte",
|
|
880
|
+
"complex64",
|
|
881
|
+
"complex128",
|
|
882
|
+
"error",
|
|
883
|
+
"float32",
|
|
884
|
+
"float64",
|
|
885
|
+
"int",
|
|
886
|
+
"int8",
|
|
887
|
+
"int16",
|
|
888
|
+
"int32",
|
|
889
|
+
"int64",
|
|
890
|
+
"rune",
|
|
891
|
+
"string",
|
|
892
|
+
"uint",
|
|
893
|
+
"uint8",
|
|
894
|
+
"uint16",
|
|
895
|
+
"uint32",
|
|
896
|
+
"uint64",
|
|
897
|
+
"uintptr",
|
|
898
|
+
"any"
|
|
899
|
+
]);
|
|
900
|
+
var BUILTINS = /* @__PURE__ */ new Set([
|
|
901
|
+
"make",
|
|
902
|
+
"len",
|
|
903
|
+
"cap",
|
|
904
|
+
"new",
|
|
905
|
+
"append",
|
|
906
|
+
"copy",
|
|
907
|
+
"close",
|
|
908
|
+
"delete",
|
|
909
|
+
"complex",
|
|
910
|
+
"real",
|
|
911
|
+
"imag",
|
|
912
|
+
"panic",
|
|
913
|
+
"recover",
|
|
914
|
+
"print",
|
|
915
|
+
"println"
|
|
916
|
+
]);
|
|
917
|
+
var tokenizeGo = (source) => {
|
|
918
|
+
const tokens = [];
|
|
919
|
+
const len = source.length;
|
|
920
|
+
let i = 0;
|
|
921
|
+
while (i < len) {
|
|
922
|
+
const ch = source[i];
|
|
923
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
924
|
+
i++;
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (ch === "/" && source[i + 1] === "/") {
|
|
928
|
+
const pos = i;
|
|
929
|
+
i += 2;
|
|
930
|
+
while (i < len && source[i] !== "\n") i++;
|
|
931
|
+
tokens.push({ type: "comment", start: pos, end: i });
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
if (ch === "/" && source[i + 1] === "*") {
|
|
935
|
+
const pos = i;
|
|
936
|
+
i += 2;
|
|
937
|
+
while (i < len && !(source[i] === "*" && source[i + 1] === "/")) i++;
|
|
938
|
+
i += 2;
|
|
939
|
+
tokens.push({ type: "comment", start: pos, end: i });
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
if (ch === "`") {
|
|
943
|
+
const pos = i;
|
|
944
|
+
i++;
|
|
945
|
+
while (i < len && source[i] !== "`") i++;
|
|
946
|
+
i++;
|
|
947
|
+
tokens.push({ type: "string", start: pos, end: i });
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
if (ch === '"') {
|
|
951
|
+
const pos = i;
|
|
952
|
+
i++;
|
|
953
|
+
while (i < len && source[i] !== '"' && source[i] !== "\n") {
|
|
954
|
+
if (source[i] === "\\") i++;
|
|
955
|
+
i++;
|
|
956
|
+
}
|
|
957
|
+
if (i < len && source[i] === '"') i++;
|
|
958
|
+
tokens.push({ type: "string", start: pos, end: i });
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (ch === "'") {
|
|
962
|
+
const pos = i;
|
|
963
|
+
i++;
|
|
964
|
+
while (i < len && source[i] !== "'" && source[i] !== "\n") {
|
|
965
|
+
if (source[i] === "\\") i++;
|
|
966
|
+
i++;
|
|
967
|
+
}
|
|
968
|
+
if (i < len && source[i] === "'") i++;
|
|
969
|
+
tokens.push({ type: "string", start: pos, end: i });
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (ch >= "0" && ch <= "9" || ch === "." && i + 1 < len && source[i + 1] >= "0" && source[i + 1] <= "9") {
|
|
973
|
+
const pos = i;
|
|
974
|
+
if (ch === "0" && (source[i + 1] === "x" || source[i + 1] === "X")) {
|
|
975
|
+
i += 2;
|
|
976
|
+
while (i < len && /[0-9a-fA-F_]/.test(source[i])) i++;
|
|
977
|
+
} else if (ch === "0" && (source[i + 1] === "b" || source[i + 1] === "B")) {
|
|
978
|
+
i += 2;
|
|
979
|
+
while (i < len && /[01_]/.test(source[i])) i++;
|
|
980
|
+
} else if (ch === "0" && (source[i + 1] === "o" || source[i + 1] === "O")) {
|
|
981
|
+
i += 2;
|
|
982
|
+
while (i < len && /[0-7_]/.test(source[i])) i++;
|
|
983
|
+
} else {
|
|
984
|
+
while (i < len && /[0-9_.]/.test(source[i])) i++;
|
|
985
|
+
if (i < len && (source[i] === "e" || source[i] === "E")) {
|
|
986
|
+
i++;
|
|
987
|
+
if (i < len && (source[i] === "+" || source[i] === "-")) i++;
|
|
988
|
+
while (i < len && source[i] >= "0" && source[i] <= "9") i++;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (i < len && source[i] === "i") i++;
|
|
992
|
+
tokens.push({ type: "number", start: pos, end: i });
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (/[a-zA-Z_]/.test(ch)) {
|
|
996
|
+
const pos = i;
|
|
997
|
+
i++;
|
|
998
|
+
while (i < len && /[a-zA-Z0-9_]/.test(source[i])) i++;
|
|
999
|
+
const word = source.slice(pos, i);
|
|
1000
|
+
let j = i;
|
|
1001
|
+
while (j < len && (source[j] === " " || source[j] === " ")) j++;
|
|
1002
|
+
if (KEYWORDS3.has(word)) {
|
|
1003
|
+
tokens.push({ type: "keyword", start: pos, end: i });
|
|
1004
|
+
} else if (TYPES2.has(word)) {
|
|
1005
|
+
tokens.push({ type: "type", start: pos, end: i });
|
|
1006
|
+
} else if (BUILTINS.has(word) && source[j] === "(") {
|
|
1007
|
+
tokens.push({ type: "function", start: pos, end: i });
|
|
1008
|
+
} else if (source[j] === "(") {
|
|
1009
|
+
tokens.push({ type: "function", start: pos, end: i });
|
|
1010
|
+
} else if (word[0] >= "A" && word[0] <= "Z") {
|
|
1011
|
+
tokens.push({ type: "type", start: pos, end: i });
|
|
1012
|
+
} else {
|
|
1013
|
+
tokens.push({ type: "variable", start: pos, end: i });
|
|
1014
|
+
}
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if ("+-*/%=<>!&|^~:".includes(ch)) {
|
|
1018
|
+
const pos = i;
|
|
1019
|
+
i++;
|
|
1020
|
+
while (i < len && "+-*/%=<>!&|^~:".includes(source[i])) i++;
|
|
1021
|
+
tokens.push({ type: "operator", start: pos, end: i });
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
if ("(){}[];,.".includes(ch)) {
|
|
1025
|
+
tokens.push({ type: "punctuation", start: i, end: i + 1 });
|
|
1026
|
+
i++;
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
tokens.push({ type: "plain", start: i, end: i + 1 });
|
|
1030
|
+
i++;
|
|
1031
|
+
}
|
|
1032
|
+
return tokens;
|
|
1033
|
+
};
|
|
1034
|
+
|
|
663
1035
|
// src/languages/builtin.ts
|
|
664
1036
|
registerLanguage({
|
|
665
1037
|
name: "JavaScript",
|
|
@@ -682,6 +1054,16 @@ registerLanguage({
|
|
|
682
1054
|
aliases: ["php"],
|
|
683
1055
|
tokenize: tokenizePhp
|
|
684
1056
|
});
|
|
1057
|
+
registerLanguage({
|
|
1058
|
+
name: "Python",
|
|
1059
|
+
aliases: ["py", "python"],
|
|
1060
|
+
tokenize: tokenizePython
|
|
1061
|
+
});
|
|
1062
|
+
registerLanguage({
|
|
1063
|
+
name: "Go",
|
|
1064
|
+
aliases: ["go", "golang"],
|
|
1065
|
+
tokenize: tokenizeGo
|
|
1066
|
+
});
|
|
685
1067
|
var iconBtnClass = "inline-flex items-center justify-center rounded-md p-1 text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-200";
|
|
686
1068
|
function LanguageSelector() {
|
|
687
1069
|
const { language, setLanguage } = useCodeEditor();
|
|
@@ -944,14 +1326,23 @@ function useEditorEngine({
|
|
|
944
1326
|
}
|
|
945
1327
|
return count;
|
|
946
1328
|
}, [value]);
|
|
1329
|
+
const autoResize = useCallback(() => {
|
|
1330
|
+
const ta = textareaRef.current;
|
|
1331
|
+
if (!ta) return;
|
|
1332
|
+
ta.style.height = "auto";
|
|
1333
|
+
ta.style.height = ta.scrollHeight + "px";
|
|
1334
|
+
}, []);
|
|
947
1335
|
useEffect(() => {
|
|
948
1336
|
const ta = textareaRef.current;
|
|
949
|
-
if (!ta
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1337
|
+
if (!ta) return;
|
|
1338
|
+
if (ta.value !== value) {
|
|
1339
|
+
const { selectionStart, selectionEnd } = ta;
|
|
1340
|
+
ta.value = value;
|
|
1341
|
+
ta.selectionStart = selectionStart;
|
|
1342
|
+
ta.selectionEnd = selectionEnd;
|
|
1343
|
+
}
|
|
1344
|
+
autoResize();
|
|
1345
|
+
}, [value, autoResize]);
|
|
955
1346
|
const updateCursorInfo = useCallback(() => {
|
|
956
1347
|
const ta = textareaRef.current;
|
|
957
1348
|
if (!ta) return;
|
|
@@ -968,8 +1359,9 @@ function useEditorEngine({
|
|
|
968
1359
|
const ta = textareaRef.current;
|
|
969
1360
|
if (!ta) return;
|
|
970
1361
|
onChangeRef.current?.(ta.value);
|
|
1362
|
+
autoResize();
|
|
971
1363
|
updateCursorInfo();
|
|
972
|
-
}, [updateCursorInfo]);
|
|
1364
|
+
}, [autoResize, updateCursorInfo]);
|
|
973
1365
|
const handleSelect = useCallback(() => {
|
|
974
1366
|
updateCursorInfo();
|
|
975
1367
|
}, [updateCursorInfo]);
|
|
@@ -1029,6 +1421,7 @@ function useEditorEngine({
|
|
|
1029
1421
|
ta.selectionStart = ta.selectionEnd = start + tabSize;
|
|
1030
1422
|
onChangeRef.current?.(ta.value);
|
|
1031
1423
|
}
|
|
1424
|
+
autoResize();
|
|
1032
1425
|
updateCursorInfo();
|
|
1033
1426
|
return;
|
|
1034
1427
|
}
|
|
@@ -1047,11 +1440,12 @@ function useEditorEngine({
|
|
|
1047
1440
|
ta.value = before + insertion + after;
|
|
1048
1441
|
ta.selectionStart = ta.selectionEnd = start + insertion.length;
|
|
1049
1442
|
onChangeRef.current?.(ta.value);
|
|
1443
|
+
autoResize();
|
|
1050
1444
|
updateCursorInfo();
|
|
1051
1445
|
return;
|
|
1052
1446
|
}
|
|
1053
1447
|
},
|
|
1054
|
-
[readOnly, tabSize, updateCursorInfo]
|
|
1448
|
+
[readOnly, tabSize, autoResize, updateCursorInfo]
|
|
1055
1449
|
);
|
|
1056
1450
|
return {
|
|
1057
1451
|
textareaRef,
|