ar-design 0.2.49 → 0.2.51

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.
@@ -36,7 +36,7 @@
36
36
  }
37
37
  .ar-dnd > div.end-item {
38
38
  /* Sırasıyla; Ad, Süre, Hız, Gecikme Süresi, Tekrar Sayısı, Yön, Bitiş Süreci */
39
- animation: endItem ease-in-out 1000ms 0s 1 normal both;
39
+ animation: endItem ease-in-out 1s 0s 1 normal both;
40
40
  }
41
41
 
42
42
  .ar-dnd > div > .move {
@@ -136,6 +136,7 @@
136
136
  border-bottom: none;
137
137
  }
138
138
  .ar-table > .content > table > tbody > tr > td {
139
+ position: relative;
139
140
  z-index: 1;
140
141
  }
141
142
  .ar-table > .content > table > tbody > tr > td.type-of-number {
@@ -153,7 +154,6 @@
153
154
  justify-content: flex-end;
154
155
  align-items: center;
155
156
  }
156
-
157
157
  .ar-table > .content > table > tbody > tr > td.text-wrap {
158
158
  text-wrap: wrap;
159
159
  }
@@ -184,4 +184,50 @@
184
184
  cursor: no-drop;
185
185
  }
186
186
 
187
+ .ar-table > .content > table > tbody > tr.subrow-item {
188
+ background-color: rgba(var(--warning-rgb), 0.1);
189
+ border-bottom: solid 1px rgba(var(--warning-rgb), 0.35);
190
+ }
191
+ .ar-table > .content > table > tbody > tr.subrow-item:last-child {
192
+ background-color: rgba(var(--warning-rgb), 0.1);
193
+ border-bottom: none;
194
+ }
195
+ .ar-table > .content > table > tbody > tr.subrow-item.type-a > td:nth-child(1)::before {
196
+ position: absolute;
197
+ top: 0;
198
+ left: 0;
199
+ content: "";
200
+ background-color: rgba(var(--warning-rgb), 0.35);
201
+ width: 2px;
202
+ height: 100%;
203
+ }
204
+ .ar-table > .content > table > tbody > tr.subrow-item.type-a > td:nth-child(1)::after {
205
+ position: absolute;
206
+ top: 50%;
207
+ left: 2px;
208
+ content: "";
209
+ background-color: rgba(var(--warning-rgb), 0.35);
210
+ width: 25px;
211
+ height: 2px;
212
+ }
213
+
214
+ .ar-table > .content > table > tbody > tr.subrow-item.type-b > td:nth-child(2)::before {
215
+ position: absolute;
216
+ top: 0;
217
+ left: 0;
218
+ content: "";
219
+ background-color: rgba(var(--warning-rgb), 0.35);
220
+ width: 2px;
221
+ height: 100%;
222
+ }
223
+ .ar-table > .content > table > tbody > tr.subrow-item.type-b > td:nth-child(2)::after {
224
+ position: absolute;
225
+ top: 50%;
226
+ left: 2px;
227
+ content: "";
228
+ background-color: rgba(var(--warning-rgb), 0.35);
229
+ width: 25px;
230
+ height: 2px;
231
+ }
232
+
187
233
  @import url("./scroll.css");
@@ -55,3 +55,41 @@
55
55
  inset: 0;
56
56
  cursor: ns-resize;
57
57
  }
58
+
59
+ .ar-alias-panel {
60
+ visibility: hidden;
61
+ opacity: 0;
62
+ position: absolute;
63
+ background-color: var(--white);
64
+ width: 200px;
65
+ max-height: 250px;
66
+ border: solid 1px var(--gray-200);
67
+ border-radius: var(--border-radius-lg);
68
+ overflow-y: auto;
69
+ overflow-x: hidden;
70
+ box-shadow: 0 10px 15px -5px rgba(var(--black-rgb), 0.1);
71
+ /* Sırasıyla; Ad, Süre, Hız, Gecikme Süresi, Tekrar Sayısı, Yön, Bitiş Süreci */
72
+ animation: opened ease-in-out 250ms 0s 1 normal both;
73
+ }
74
+ .ar-alias-panel > ul > li {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 0 0.5rem;
78
+ padding: 0 1rem;
79
+ height: var(--input-height);
80
+ cursor: pointer;
81
+ }
82
+ .ar-alias-panel > ul > li:hover {
83
+ background-color: var(--gray-100);
84
+ }
85
+
86
+ @keyframes opened {
87
+ from {
88
+ visibility: hidden;
89
+ opacity: 0;
90
+ }
91
+ to {
92
+ visibility: visible;
93
+ opacity: 1;
94
+ }
95
+ }
@@ -21,7 +21,7 @@ const Table = forwardRef(({ children, title, description, data, columns, actions
21
21
  // variables
22
22
  const _subrowOpenAutomatically = config.subrow?.openAutomatically ?? false;
23
23
  const _subrowSelector = config.subrow?.selector ?? "subitems";
24
- const _subrowButton = config.subrow?.button ?? false;
24
+ const _subrowButton = config.subrow?.button ?? true;
25
25
  // className
26
26
  const _tableClassName = ["ar-table", "scroll"];
27
27
  // states
@@ -217,6 +217,28 @@ const Table = forwardRef(({ children, title, description, data, columns, actions
217
217
  setTimeout(() => handleScroll(), 0);
218
218
  return _data;
219
219
  }, [data, searchedText, currentPage]);
220
+ const renderRow = (item, index) => {
221
+ const isHasSubitems = _subrowSelector in item;
222
+ // TODO: Keylere bakılacak...
223
+ return (React.createElement(Fragment, { key: `row-${index}` },
224
+ React.createElement("tr", { key: `row-${index}` },
225
+ selections && (React.createElement("td", { className: "sticky-left", "data-sticky-position": "left" },
226
+ React.createElement(Checkbox, { ref: (element) => (_checkboxItems.current[index] = element), status: "primary", checked: selectionItems.some((selectionItem) => JSON.stringify(selectionItem) === JSON.stringify(item)), onChange: (event) => {
227
+ if (event.target.checked)
228
+ setSelectionItems((prev) => [...prev, item]);
229
+ else
230
+ setSelectionItems((prev) => prev.filter((_item) => _item !== item));
231
+ } }))),
232
+ _subrowButton && isHasSubitems ? (React.createElement("td", null, item[_subrowSelector] && (React.createElement("div", { className: "subitem-open-button-wrapper" },
233
+ React.createElement("span", { className: `subitem-open-button ${(showSubitems[index] && "opened") ?? ""}`, onClick: () => {
234
+ setShowSubitems((prev) => ({
235
+ ...prev,
236
+ [`${index}`]: !prev[`${index}`],
237
+ }));
238
+ } }))))) : _subrowButton ? (React.createElement("td", { style: { width: 0, minWidth: 0 } })) : null,
239
+ columns.map((c, cIndex) => renderCell(item, c, cIndex, index, 0))),
240
+ showSubitems[index] && item[_subrowSelector] && (React.createElement(SubitemList, { items: item[_subrowSelector], columns: columns, index: index, depth: 1.5 }))));
241
+ };
220
242
  const renderCell = (item, c, cIndex, index, depth) => {
221
243
  let render;
222
244
  // `c.key` bir string ise
@@ -241,38 +263,16 @@ const Table = forwardRef(({ children, title, description, data, columns, actions
241
263
  _className.push(`align-content-${c.config.alignContent}`);
242
264
  if (c.config?.textWrap)
243
265
  _className.push(`text-${c.config.textWrap}`);
244
- return (React.createElement("td", { key: `cell-${index}-${cIndex}`, className: _className.join(" "), style: c.config?.width ? { minWidth: c.config.width, maxWidth: c.config.width, paddingLeft: `${depth}rem` } : {}, "data-sticky-position": c.config?.sticky },
245
- React.createElement("div", { className: "table-cell" }, React.isValidElement(render) ? render : String(render))));
246
- };
247
- const renderRow = (item, index) => {
248
- const isHasSubitems = _subrowSelector in item;
249
- // TODO: Keylere bakılacak...
250
- return (React.createElement(Fragment, { key: `row-${index}` },
251
- React.createElement("tr", { key: `row-${index}` },
252
- selections && (React.createElement("td", { className: "sticky-left", "data-sticky-position": "left" },
253
- React.createElement(Checkbox, { ref: (element) => (_checkboxItems.current[index] = element), status: "primary", checked: selectionItems.some((selectionItem) => JSON.stringify(selectionItem) === JSON.stringify(item)), onChange: (event) => {
254
- if (event.target.checked)
255
- setSelectionItems((prev) => [...prev, item]);
256
- else
257
- setSelectionItems((prev) => prev.filter((_item) => _item !== item));
258
- } }))),
259
- _subrowButton && isHasSubitems ? (React.createElement("td", null, item[_subrowSelector] && (React.createElement("div", { className: "subitem-open-button-wrapper" },
260
- React.createElement("span", { className: `subitem-open-button ${(showSubitems[index] && "opened") ?? ""}`, onClick: () => {
261
- setShowSubitems((prev) => ({
262
- ...prev,
263
- [`${index}`]: !prev[`${index}`],
264
- }));
265
- } }))))) : _subrowButton ? (React.createElement("td", { style: { width: 0, minWidth: 0 } })) : null,
266
- columns.map((c, cIndex) => renderCell(item, c, cIndex, index, 0))),
267
- showSubitems[index] && item[_subrowSelector] && (React.createElement(SubitemList, { items: item[_subrowSelector], columns: columns, index: index, depth: 1.5 }))));
266
+ return (React.createElement("td", { key: `cell-${index}-${cIndex}`, className: _className.join(" "), style: c.config?.width ? { minWidth: c.config.width, maxWidth: c.config.width } : {}, "data-sticky-position": c.config?.sticky },
267
+ React.createElement("div", { style: { paddingLeft: `${depth}rem` }, className: "table-cell" }, React.isValidElement(render) ? render : String(render))));
268
268
  };
269
269
  const SubitemList = ({ items, columns, index, depth }) => {
270
270
  return items.map((subitem, subindex) => {
271
271
  const _subitem = subitem[_subrowSelector];
272
272
  // TODO: Keylere bakılacak...
273
273
  return (React.createElement(Fragment, { key: `subitem-${index}-${subindex}-${Math.random()}` },
274
- React.createElement("tr", { key: `subitem-${index}-${subindex}-${Math.random()}` },
275
- _subrowSelector in subitem && _subrowButton && (React.createElement("td", { style: { paddingLeft: `${depth}rem` } },
274
+ React.createElement("tr", { key: `subitem-${index}-${subindex}-${Math.random()}`, className: `subrow-item ${_subrowButton ? "type-b" : "type-a"}` },
275
+ _subrowSelector in subitem && _subrowButton ? (React.createElement("td", null,
276
276
  React.createElement("div", { className: "subitem-open-button-wrapper" },
277
277
  React.createElement("span", { className: `${(showSubitems[`${index}.${subindex}`] && "opened") ?? ""} ${!_subitem && "passive"}`, onClick: () => {
278
278
  if (!_subitem)
@@ -281,7 +281,7 @@ const Table = forwardRef(({ children, title, description, data, columns, actions
281
281
  ...prev,
282
282
  [`${index}.${subindex}`]: !prev[`${index}.${subindex}`],
283
283
  }));
284
- } })))),
284
+ } })))) : _subrowButton ? (React.createElement("td", { style: { width: 0, minWidth: 0 } })) : null,
285
285
  columns.map((c, cIndex) => renderCell(subitem, c, cIndex, subindex, depth * 1.5))),
286
286
  showSubitems[`${index}.${subindex}`] && _subitem && (React.createElement(SubitemList, { key: `subitem-${index}-${subindex}-${Math.random()}`, items: _subitem, columns: columns, index: subindex, depth: depth * 1.5 }))));
287
287
  });
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
2
  import "../../../assets/css/components/form/button/styles.css";
3
3
  import IProps from "./IProps";
4
- declare const Button: React.ForwardRefExoticComponent<IProps & React.RefAttributes<HTMLButtonElement>>;
4
+ declare const Button: React.FC<IProps>;
5
5
  export default Button;
@@ -1,22 +1,9 @@
1
1
  "use client";
2
- import React, { forwardRef, useRef } from "react";
2
+ import React, { useRef } from "react";
3
3
  import "../../../assets/css/components/form/button/styles.css";
4
4
  import Utils from "../../../libs/infrastructure/shared/Utils";
5
5
  import Tooltip from "../../feedback/tooltip";
6
- // const Button: React.FC<IProps> = ({
7
- // children,
8
- // variant = "filled",
9
- // shape,
10
- // status = "primary",
11
- // border,
12
- // size = "normal",
13
- // tooltip,
14
- // position,
15
- // icon,
16
- // upperCase,
17
- // ...attributes
18
- // }) => {
19
- const Button = forwardRef(({ children, variant = "filled", shape, status = "primary", border, size = "normal", tooltip, position, icon, upperCase, ...attributes }, ref) => {
6
+ const Button = ({ children, variant = "filled", shape, status = "primary", border, size = "normal", tooltip, position, icon, upperCase, ...attributes }) => {
20
7
  // refs
21
8
  const _button = useRef(null);
22
9
  const _buttonClassName = ["ar-button"];
@@ -29,7 +16,7 @@ const Button = forwardRef(({ children, variant = "filled", shape, status = "prim
29
16
  _buttonClassName.push(position.type);
30
17
  _buttonClassName.push(position.inset.map((_inset) => _inset).join(" "));
31
18
  }
32
- const buttonElement = (React.createElement("button", { ref: ref ?? _button, ...attributes, className: _buttonClassName.map((c) => c).join(" "), onClick: (event) => {
19
+ const buttonElement = (React.createElement("button", { ref: _button, ...attributes, className: _buttonClassName.map((c) => c).join(" "), onClick: (event) => {
33
20
  // Disabled gelmesi durumunda işlem yapmasına izin verme...
34
21
  if (attributes.disabled)
35
22
  return;
@@ -39,7 +26,7 @@ const Button = forwardRef(({ children, variant = "filled", shape, status = "prim
39
26
  if (_current && !_current.classList.contains(addClass)) {
40
27
  // Sınıf ekleniyor...
41
28
  _current.classList.add(addClass);
42
- // Sınıf 750 milisaniye sonra kaldırlacak.
29
+ // Sınıf 500 milisaniye sonra kaldırlacak.
43
30
  setTimeout(() => _current.classList.remove(addClass), 750);
44
31
  }
45
32
  })();
@@ -49,6 +36,6 @@ const Button = forwardRef(({ children, variant = "filled", shape, status = "prim
49
36
  icon?.element,
50
37
  React.createElement("span", null, !shape ? (typeof children === "string" && upperCase ? children.toLocaleUpperCase() : children) : ""))));
51
38
  return !tooltip ? (buttonElement) : (React.createElement(Tooltip, { text: tooltip.text, direction: tooltip.direction }, buttonElement));
52
- });
39
+ };
53
40
  Button.displayName = "Button";
54
41
  export default Button;
@@ -1,8 +1,16 @@
1
1
  import { IValidation } from "../../../libs/types/IGlobalProps";
2
- interface IProps extends IValidation {
2
+ interface IProps<T> extends IValidation {
3
3
  name?: string;
4
4
  value?: string;
5
5
  onChange: (value?: string) => void;
6
+ dynamicList?: {
7
+ render: {
8
+ display: keyof T;
9
+ items: T[];
10
+ };
11
+ triggerKey?: string;
12
+ onTagged?: (tagged: any[]) => void;
13
+ };
6
14
  placeholder?: string;
7
15
  height?: number;
8
16
  multilang?: boolean;
@@ -1,5 +1,5 @@
1
1
  import "../../../assets/css/components/form/text-editor/styles.css";
2
2
  import IProps from "./IProps";
3
3
  import React from "react";
4
- declare const TextEditor: React.FC<IProps>;
4
+ declare const TextEditor: <T extends object>({ name, value, onChange, dynamicList, height, validation, }: IProps<T>) => React.JSX.Element;
5
5
  export default TextEditor;
@@ -4,15 +4,28 @@ import { ARIcon } from "../../icons";
4
4
  import Button from "../button";
5
5
  import React, { useEffect, useRef, useState } from "react";
6
6
  import Utils from "../../../libs/infrastructure/shared/Utils";
7
- const TextEditor = ({ name, value, onChange, placeholder, height, multilang, validation }) => {
7
+ import ReactDOM from "react-dom";
8
+ const TextEditor = ({ name, value, onChange, dynamicList,
9
+ // placeholder,
10
+ height,
11
+ // multilang,
12
+ validation, }) => {
8
13
  // refs
9
14
  const _container = useRef(null);
10
15
  const _arIframe = useRef(null);
11
16
  const _onChange = useRef(onChange);
12
17
  const _onChangeTimeOut = useRef(null);
18
+ // refs -> Alias Panel
19
+ const _target = useRef(null);
20
+ const _arAliasPanel = useRef(null);
13
21
  // states
14
22
  const [iframe, setIframe] = useState(null);
15
23
  const [iframeDocument, setIframeDocument] = useState(undefined);
24
+ // states -> Data
25
+ const [tagged, setTagged] = useState([]);
26
+ // states -> Alias Panel
27
+ const [atRect, setAtRect] = useState(null);
28
+ const [filtered, setFiltered] = useState(null);
16
29
  // variables
17
30
  const toolbarButtons = [
18
31
  { command: "bold", icon: "Bold", tooltip: `Bold (${Utils.GetOSShortCutIcons()} + B)` },
@@ -35,7 +48,10 @@ const TextEditor = ({ name, value, onChange, placeholder, height, multilang, val
35
48
  iframeDoc.execCommand(command, true, undefined);
36
49
  };
37
50
  const handleFocus = () => _arIframe.current?.classList.add("focused");
38
- const handleBlur = () => _arIframe.current?.classList.remove("focused");
51
+ const handleBlur = () => {
52
+ _arIframe.current?.classList.remove("focused");
53
+ // setAtRect(null);
54
+ };
39
55
  const handleMouseDown = () => {
40
56
  // Resizebar a tıklandığında iframe içerisinde bulunan window'un event listenerı olmadığı için orada resize çalışmayacaktır.
41
57
  // Bu yüzden önüne bir duvar örüyoruz ve mevcut sayfanın window'unda işlem yapmaya devam ediyor.
@@ -55,6 +71,44 @@ const TextEditor = ({ name, value, onChange, placeholder, height, multilang, val
55
71
  _arIframe.current.style.height = `${height}px`;
56
72
  }
57
73
  };
74
+ // methods -> Alias Panel
75
+ const handleBackSpaceKeydown = (event) => {
76
+ const key = event.key;
77
+ if (key === "Backspace" || key === "Delete") {
78
+ const selection = _arIframe.current?.contentDocument?.getSelection();
79
+ if (!selection || selection.rangeCount === 0)
80
+ return;
81
+ const range = selection.getRangeAt(0);
82
+ // 1. Çoklu seçim varsa: clone edip span'ları bul.
83
+ const contents = range.cloneContents();
84
+ const multiSpans = contents.querySelectorAll("span[data-tag]");
85
+ if (multiSpans.length > 0) {
86
+ event.preventDefault();
87
+ const tagsToRemove = [];
88
+ multiSpans.forEach((span) => {
89
+ const tag = span.getAttribute("data-tag");
90
+ if (tag)
91
+ tagsToRemove.push(tag);
92
+ });
93
+ // DOM'dan temizle
94
+ range.deleteContents();
95
+ // State'ten temizle
96
+ setTagged((prev) => prev.filter((x) => tagsToRemove.every((tag) => !JSON.stringify(x).includes(tag))));
97
+ return;
98
+ }
99
+ // 2. Tekli seçim: caret bir span içindeyse sil
100
+ const node = selection.anchorNode;
101
+ const container = node?.parentElement;
102
+ if (container?.tagName === "SPAN" && container.dataset.tag) {
103
+ event.preventDefault();
104
+ const tag = container.dataset.tag;
105
+ // DOM'dan sil
106
+ container.remove();
107
+ // State'ten kaldır
108
+ setTagged((prev) => prev.filter((x) => !JSON.stringify(x).includes(tag ?? "")));
109
+ }
110
+ }
111
+ };
58
112
  // useEffects
59
113
  useEffect(() => {
60
114
  // Iframe Document yüklendikten sonra çalışacaktır.
@@ -94,7 +148,32 @@ const TextEditor = ({ name, value, onChange, placeholder, height, multilang, val
94
148
  if (_onChangeTimeOut.current)
95
149
  clearTimeout(_onChangeTimeOut.current);
96
150
  _onChangeTimeOut.current = setTimeout(() => {
97
- mutationsList.forEach(() => {
151
+ mutationsList.forEach((record) => {
152
+ const target = record.target;
153
+ _target.current = record.target;
154
+ if (dynamicList) {
155
+ if (target.nodeType === Node.TEXT_NODE) {
156
+ const text = target.textContent ?? "";
157
+ const atIndex = text.lastIndexOf(dynamicList?.triggerKey ?? "@");
158
+ if (atIndex !== -1) {
159
+ const afterAt = text.slice(atIndex + 1); // @ sonrası metin.
160
+ const hasWhitespace = /\s/.test(afterAt);
161
+ if (!hasWhitespace) {
162
+ const selection = _iframeDocument?.getSelection();
163
+ if (selection && selection.rangeCount > 0) {
164
+ const range = selection.getRangeAt(0).cloneRange();
165
+ const rect = range.getBoundingClientRect();
166
+ range.collapse(true);
167
+ setAtRect(rect);
168
+ setFiltered(afterAt);
169
+ return;
170
+ }
171
+ }
172
+ }
173
+ // Eğer @ yoksa ya da boşluk varsa paneli kapat.
174
+ setAtRect(null);
175
+ }
176
+ }
98
177
  _iframeDocument?.body.innerHTML === "<br>"
99
178
  ? _onChange.current(undefined)
100
179
  : _onChange.current(_iframeDocument.body.innerHTML);
@@ -105,12 +184,21 @@ const TextEditor = ({ name, value, onChange, placeholder, height, multilang, val
105
184
  observer.observe(_iframeDocument.body, { childList: true, subtree: true, characterData: true, attributes: true });
106
185
  _iframeDocument.body.addEventListener("focus", handleFocus);
107
186
  _iframeDocument.body.addEventListener("blur", handleBlur);
187
+ if (dynamicList) {
188
+ _iframeDocument.body.addEventListener("keydown", handleBackSpaceKeydown);
189
+ }
108
190
  return () => {
109
191
  observer.disconnect();
110
- _iframeDocument?.body.removeEventListener("focus", handleFocus);
111
- _iframeDocument?.body.removeEventListener("blur", handleBlur);
192
+ _iframeDocument.body.removeEventListener("focus", handleFocus);
193
+ _iframeDocument.body.removeEventListener("blur", handleBlur);
194
+ if (dynamicList) {
195
+ _iframeDocument.body.removeEventListener("keydown", handleBackSpaceKeydown);
196
+ }
112
197
  };
113
198
  }, [iframe]);
199
+ useEffect(() => {
200
+ dynamicList?.onTagged && dynamicList?.onTagged(tagged);
201
+ }, [tagged]);
114
202
  useEffect(() => {
115
203
  if (!_arIframe.current)
116
204
  return;
@@ -128,6 +216,67 @@ const TextEditor = ({ name, value, onChange, placeholder, height, multilang, val
128
216
  text: tooltip,
129
217
  }, onClick: () => execCommand(command) })))),
130
218
  React.createElement("div", { className: "resize", onMouseDown: handleMouseDown }),
131
- validation?.text && React.createElement("span", { className: "validation" }, validation.text)));
219
+ validation?.text && React.createElement("span", { className: "validation" }, validation.text),
220
+ dynamicList &&
221
+ atRect &&
222
+ ReactDOM.createPortal(React.createElement("div", { ref: _arAliasPanel, className: "ar-alias-panel", style: {
223
+ top: (_arIframe.current?.getBoundingClientRect().top ?? 0) + atRect.top + 20,
224
+ left: (_arIframe.current?.getBoundingClientRect().left ?? 0) + atRect.left,
225
+ }, onClick: () => {
226
+ setAtRect(null);
227
+ } },
228
+ React.createElement("ul", null, dynamicList &&
229
+ dynamicList.render.items
230
+ // .filter((fItem) => !tagged.some((t: T) => JSON.stringify(fItem) === JSON.stringify(t)))
231
+ .filter((item) => {
232
+ const displayText = item[dynamicList.render.display] ?? "";
233
+ return displayText.toLowerCase().includes(filtered.toLowerCase());
234
+ })
235
+ .map((item, index) => (React.createElement("li", { key: index, onClick: (event) => {
236
+ event.stopPropagation();
237
+ const selection = iframeDocument?.getSelection();
238
+ const target = _target.current;
239
+ if (selection && selection.rangeCount > 0 && target && target.nodeType === Node.TEXT_NODE) {
240
+ const text = target.textContent ?? "";
241
+ const atIndex = text.lastIndexOf(dynamicList?.triggerKey ?? "@");
242
+ if (atIndex !== -1) {
243
+ const range = selection.getRangeAt(0).cloneRange();
244
+ range.setStart(target, atIndex);
245
+ range.setEnd(target, text.length);
246
+ range.deleteContents();
247
+ const itemText = item[dynamicList.render.display] ?? "";
248
+ const span = iframeDocument?.createElement("span");
249
+ const spaceNode = iframeDocument?.createTextNode(" \u200B");
250
+ if (span && spaceNode && iframeDocument) {
251
+ span.setAttribute("data-tag", `${itemText}`);
252
+ span.style.backgroundColor = "rgba(114, 15, 103, .1)";
253
+ span.style.padding = "0 5px";
254
+ span.style.borderRadius = "2px";
255
+ span.style.color = "#720f67";
256
+ span.style.fontWeight = "bold";
257
+ span.textContent = `@${itemText}`;
258
+ // Yeni bir wrapper fragment oluştur
259
+ const fragment = iframeDocument.createDocumentFragment();
260
+ fragment.appendChild(span);
261
+ fragment.appendChild(spaceNode); // görünmez boş node, ama yazılabilir
262
+ range.insertNode(fragment);
263
+ // Cursor'u spaceNode’un sonuna yerleştir
264
+ const newRange = iframeDocument.createRange();
265
+ newRange.setStart(spaceNode, spaceNode.length);
266
+ newRange.collapse(true);
267
+ selection.removeAllRanges();
268
+ selection.addRange(newRange);
269
+ // Focus zaten varsa sorun olmayacak
270
+ const activeEl = iframeDocument?.activeElement;
271
+ activeEl?.focus();
272
+ }
273
+ setAtRect(null);
274
+ setTagged((prev) => {
275
+ const exists = prev.some((i) => JSON.stringify(i) === JSON.stringify(item));
276
+ return exists ? prev : [...prev, item];
277
+ });
278
+ }
279
+ }
280
+ } }, item[dynamicList.render.display] ?? ""))))), document.body)));
132
281
  };
133
282
  export default TextEditor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ar-design",
3
- "version": "0.2.49",
3
+ "version": "0.2.51",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",