ar-design 0.4.63 → 0.4.64
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/assets/css/components/data-display/card/styles.css +2 -2
- package/dist/assets/css/components/data-display/dnd/styles.css +3 -3
- package/dist/assets/css/components/data-display/syntax-highlighter/syntax-highlighter.css +2 -2
- package/dist/assets/css/components/feedback/alert/styles.css +2 -2
- package/dist/assets/css/components/feedback/drawer/styles.css +3 -3
- package/dist/assets/css/components/feedback/modal/styles.css +15 -11
- package/dist/assets/css/components/feedback/progress/progress.css +3 -3
- package/dist/assets/css/components/form/button/styles.css +10 -7
- package/dist/assets/css/components/form/checkbox/checkbox.css +2 -2
- package/dist/assets/css/components/form/date-picker/date-picker.css +10 -10
- package/dist/assets/css/components/form/input/styles.css +15 -12
- package/dist/assets/css/components/form/radio/radio.css +2 -2
- package/dist/assets/css/components/form/select/styles.css +2 -2
- package/dist/assets/css/components/form/switch/styles.css +7 -3
- package/dist/assets/css/components/layout/layout.css +10 -10
- package/dist/assets/css/components/navigation/steps/styles.css +5 -3
- package/dist/assets/css/core/ar-core.css +25 -20
- package/dist/assets/css/core/utils.css +3 -0
- package/dist/components/data-display/table/FilterPopup.js +8 -12
- package/dist/components/data-display/table/PropertiesPopup.js +10 -19
- package/dist/components/data-display/table/THeadCell.js +9 -8
- package/dist/components/data-display/table/body/TBody.js +53 -37
- package/dist/components/data-display/table/index.js +68 -175
- package/dist/components/feedback/popover/index.js +6 -0
- package/dist/components/feedback/tooltip/index.js +63 -16
- package/dist/components/form/date-picker/Props.d.ts +0 -1
- package/dist/components/form/input/otp/Otp.js +94 -79
- package/dist/components/form/radio/IProps.d.ts +0 -22
- package/dist/components/form/switch/IProps.d.ts +0 -11
- package/package.json +2 -2
|
@@ -9,6 +9,12 @@ const Tooltip = ({ children, text, direction = "top" }) => {
|
|
|
9
9
|
// states
|
|
10
10
|
const [mouseEnter, setMouseEnter] = useState(false);
|
|
11
11
|
const [_direction, setDirection] = useState(direction);
|
|
12
|
+
// 💡 Donma ve sonsuz döngüyü engellemek için dışarıdan seçilen ana yönü bir ref'te saklıyoruz
|
|
13
|
+
const currentInitialDirection = useRef(direction);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
currentInitialDirection.current = direction;
|
|
16
|
+
setDirection(direction); // Storybook panelinden elle yön değiştiğinde senkronize et
|
|
17
|
+
}, [direction]);
|
|
12
18
|
// methods
|
|
13
19
|
const handlePosition = useCallback(() => {
|
|
14
20
|
const child = _children.current;
|
|
@@ -17,21 +23,46 @@ const Tooltip = ({ children, text, direction = "top" }) => {
|
|
|
17
23
|
return;
|
|
18
24
|
const margin = 17.5;
|
|
19
25
|
const windowWidth = window.innerWidth;
|
|
20
|
-
const
|
|
26
|
+
const windowHeight = window.innerHeight;
|
|
21
27
|
const childRect = child.getBoundingClientRect();
|
|
22
28
|
const tooltipRect = tooltip.getBoundingClientRect();
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const spaceTop = childRect.top;
|
|
30
|
+
const spaceBottom = windowHeight - childRect.bottom;
|
|
31
|
+
const spaceLeft = childRect.left;
|
|
32
|
+
const spaceRight = windowWidth - childRect.right;
|
|
33
|
+
// 💡 Hesaplamaya state'ten değil, doğrudan orijinal seçilen yönden başlıyoruz
|
|
34
|
+
let finalDirection = currentInitialDirection.current;
|
|
35
|
+
// Sıkışma durumlarına göre yönü dinamik değiştir
|
|
36
|
+
if (finalDirection === "top" && spaceTop < tooltipRect.height + margin) {
|
|
37
|
+
finalDirection = "bottom";
|
|
38
|
+
}
|
|
39
|
+
else if (finalDirection === "bottom" && spaceBottom < tooltipRect.height + margin) {
|
|
40
|
+
finalDirection = "top";
|
|
41
|
+
}
|
|
42
|
+
else if (finalDirection === "left" && spaceLeft < tooltipRect.width + margin) {
|
|
43
|
+
finalDirection = "right";
|
|
44
|
+
}
|
|
45
|
+
else if (finalDirection === "right" && spaceRight < tooltipRect.width + margin) {
|
|
46
|
+
finalDirection = "left";
|
|
47
|
+
}
|
|
48
|
+
// Eğer hala hiçbir yere sığmıyorsa en geniş boşluğu bul
|
|
49
|
+
const maxSpace = Math.max(spaceTop, spaceBottom, spaceLeft, spaceRight);
|
|
50
|
+
if ((finalDirection === "top" && spaceTop < tooltipRect.height + margin) ||
|
|
51
|
+
(finalDirection === "bottom" && spaceBottom < tooltipRect.height + margin) ||
|
|
52
|
+
(finalDirection === "left" && spaceLeft < tooltipRect.width + margin) ||
|
|
53
|
+
(finalDirection === "right" && spaceRight < tooltipRect.width + margin)) {
|
|
54
|
+
if (maxSpace === spaceTop)
|
|
55
|
+
finalDirection = "top";
|
|
56
|
+
else if (maxSpace === spaceBottom)
|
|
57
|
+
finalDirection = "bottom";
|
|
58
|
+
else if (maxSpace === spaceLeft)
|
|
59
|
+
finalDirection = "left";
|
|
60
|
+
else if (maxSpace === spaceRight)
|
|
61
|
+
finalDirection = "right";
|
|
31
62
|
}
|
|
32
63
|
let top = 0;
|
|
33
64
|
let left = 0;
|
|
34
|
-
switch (
|
|
65
|
+
switch (finalDirection) {
|
|
35
66
|
case "top":
|
|
36
67
|
top = childRect.top - tooltipRect.height - margin;
|
|
37
68
|
left = childRect.left + childRect.width / 2 - tooltipRect.width / 2;
|
|
@@ -49,12 +80,26 @@ const Tooltip = ({ children, text, direction = "top" }) => {
|
|
|
49
80
|
left = childRect.left - tooltipRect.width - margin;
|
|
50
81
|
break;
|
|
51
82
|
}
|
|
83
|
+
// Ekran taşma koruması
|
|
84
|
+
if (left < 10)
|
|
85
|
+
left = 10;
|
|
86
|
+
if (left + tooltipRect.width > windowWidth - 10) {
|
|
87
|
+
left = windowWidth - tooltipRect.width - 10;
|
|
88
|
+
}
|
|
52
89
|
tooltip.style.top = `${top}px`;
|
|
53
90
|
tooltip.style.left = `${left}px`;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
91
|
+
// 💡 KRİTİK DEĞİŞİKLİK: Sadece yön gerçekten değiştiyse state güncellenir.
|
|
92
|
+
// Bu kontrol MutationObserver'ın yarattığı kısır döngüyü anında kırar.
|
|
93
|
+
setDirection((prev) => {
|
|
94
|
+
if (prev !== finalDirection)
|
|
95
|
+
return finalDirection;
|
|
96
|
+
return prev;
|
|
97
|
+
});
|
|
98
|
+
}, []); // Bağımlılık dizisini boş bırakarak fonksiyonun kimliğini sabitliyoruz
|
|
99
|
+
// useEffects
|
|
57
100
|
useEffect(() => {
|
|
101
|
+
window.addEventListener("resize", handlePosition);
|
|
102
|
+
window.addEventListener("scroll", handlePosition, { passive: true });
|
|
58
103
|
const observer = new MutationObserver(() => {
|
|
59
104
|
handlePosition();
|
|
60
105
|
});
|
|
@@ -64,17 +109,19 @@ const Tooltip = ({ children, text, direction = "top" }) => {
|
|
|
64
109
|
subtree: true,
|
|
65
110
|
});
|
|
66
111
|
return () => {
|
|
112
|
+
window.removeEventListener("resize", handlePosition);
|
|
113
|
+
window.removeEventListener("scroll", handlePosition);
|
|
67
114
|
observer.disconnect();
|
|
68
115
|
};
|
|
69
|
-
}, []);
|
|
116
|
+
}, [handlePosition]);
|
|
70
117
|
useEffect(() => {
|
|
71
118
|
if (mouseEnter)
|
|
72
119
|
setTimeout(() => handlePosition(), 0);
|
|
73
|
-
}, [mouseEnter]);
|
|
120
|
+
}, [mouseEnter, handlePosition]);
|
|
74
121
|
return (React.createElement("div", { className: "ar-tooltip-wrapper" },
|
|
75
122
|
React.createElement("div", { ref: _children, onMouseEnter: () => setMouseEnter(true), onMouseLeave: () => setMouseEnter(false) }, children),
|
|
76
123
|
mouseEnter &&
|
|
77
|
-
ReactDOM.createPortal(React.createElement("div", { ref: _arTooltip, className: `ar-tooltip ${_direction}` }, Array.isArray(text) ? (text.map((t) => (React.createElement("span", { className: "text" },
|
|
124
|
+
ReactDOM.createPortal(React.createElement("div", { ref: _arTooltip, className: `ar-tooltip ${_direction}` }, Array.isArray(text) ? (text.map((t, index) => (React.createElement("span", { key: index, className: "text" },
|
|
78
125
|
React.createElement("span", { className: "bullet" }, "\u2022"),
|
|
79
126
|
React.createElement("span", null, t))))) : (React.createElement("span", { className: "text" }, text))), document.body)));
|
|
80
127
|
};
|
|
@@ -1,107 +1,122 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import React, { useRef, useCallback } from "react";
|
|
2
|
+
import React, { useRef, useCallback, useState, useEffect } from "react";
|
|
3
3
|
import Input from "..";
|
|
4
4
|
const Otp = ({ character, onChange, ...attributes }) => {
|
|
5
5
|
// refs
|
|
6
6
|
const _inputs = useRef([]);
|
|
7
|
-
|
|
8
|
-
const
|
|
7
|
+
// states
|
|
8
|
+
const [otpValues, setOtpValues] = useState(() => Array(character).fill(""));
|
|
9
9
|
// methods
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (_isPasteCombo.current)
|
|
14
|
-
return;
|
|
15
|
-
let { value } = event.currentTarget;
|
|
16
|
-
_value.current = { ..._value.current, [index]: value };
|
|
17
|
-
if (value.length >= 1) {
|
|
18
|
-
if (!_inputs.current[index + 1]) {
|
|
19
|
-
_inputs.current[character - 1]?.focus();
|
|
20
|
-
_inputs.current[character - 1]?.select();
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
_inputs.current[index + 1]?.focus();
|
|
24
|
-
}
|
|
25
|
-
}
|
|
10
|
+
const triggerChange = (newValues, event) => {
|
|
11
|
+
setOtpValues(newValues);
|
|
12
|
+
const combinedValue = newValues.join("");
|
|
26
13
|
onChange?.({
|
|
27
14
|
...event,
|
|
28
15
|
target: {
|
|
29
16
|
...event.currentTarget,
|
|
30
17
|
name: attributes.name ?? "",
|
|
31
|
-
value:
|
|
32
|
-
.sort((a, b) => Number(a) - Number(b))
|
|
33
|
-
.map((key) => _value.current[Number(key)])
|
|
34
|
-
.join(""),
|
|
18
|
+
value: combinedValue,
|
|
35
19
|
},
|
|
36
20
|
});
|
|
37
|
-
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
_value.current = { ..._value.current, [i]: chars[i] };
|
|
52
|
-
onChange?.({
|
|
53
|
-
...event,
|
|
54
|
-
target: {
|
|
55
|
-
...event.currentTarget,
|
|
56
|
-
name: attributes.name ?? "",
|
|
57
|
-
value: Object.keys(_value.current)
|
|
58
|
-
.sort((a, b) => Number(a) - Number(b))
|
|
59
|
-
.map((key) => _value.current[Number(key)])
|
|
60
|
-
.join(""),
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
input.focus();
|
|
64
|
-
}
|
|
65
|
-
i++;
|
|
66
|
-
if (i >= chars.length)
|
|
67
|
-
clearInterval(interval);
|
|
68
|
-
}, 50);
|
|
21
|
+
};
|
|
22
|
+
const handleKeyDown = useCallback((index) => (event) => {
|
|
23
|
+
if (attributes.disabled)
|
|
24
|
+
return;
|
|
25
|
+
const { key } = event;
|
|
26
|
+
const currentInput = _inputs.current[index];
|
|
27
|
+
// Sol / Aşağı Ok Tuşları
|
|
28
|
+
if (key === "ArrowDown" || key === "ArrowLeft") {
|
|
29
|
+
event.preventDefault(); // Tarayıcı imleç hareketini engelle
|
|
30
|
+
if (index > 0) {
|
|
31
|
+
const prevInput = _inputs.current[index - 1];
|
|
32
|
+
prevInput?.focus();
|
|
33
|
+
setTimeout(() => prevInput?.select(), 0);
|
|
34
|
+
}
|
|
69
35
|
return;
|
|
70
36
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (_isPasteCombo.current)
|
|
37
|
+
// Sağ / Yukarı Ok Tuşları
|
|
38
|
+
if (key === "ArrowUp" || key === "ArrowRight") {
|
|
39
|
+
event.preventDefault(); // Tarayıcı imleç hareketini engelle
|
|
40
|
+
if (index < character - 1) {
|
|
41
|
+
const nextInput = _inputs.current[index + 1];
|
|
42
|
+
nextInput?.focus();
|
|
43
|
+
setTimeout(() => nextInput?.select(), 0);
|
|
44
|
+
}
|
|
80
45
|
return;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
46
|
+
}
|
|
47
|
+
// Backspace (Silme) İşlemi
|
|
48
|
+
if (key === "Backspace") {
|
|
84
49
|
event.preventDefault();
|
|
85
|
-
|
|
50
|
+
const newValues = [...otpValues];
|
|
51
|
+
if (otpValues[index] !== "") {
|
|
52
|
+
// Mevcut kutu doluysa temizle
|
|
53
|
+
newValues[index] = "";
|
|
54
|
+
triggerChange(newValues, event);
|
|
55
|
+
}
|
|
56
|
+
else if (index > 0) {
|
|
57
|
+
// Mevcut kutu boşsa bir öncekini temizle ve focus ol
|
|
58
|
+
newValues[index - 1] = "";
|
|
59
|
+
triggerChange(newValues, event);
|
|
60
|
+
_inputs.current[index - 1]?.focus();
|
|
61
|
+
setTimeout(() => _inputs.current[index - 1]?.select(), 0);
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Sadece rakamlara izin ver (Meta tuşları hariç: Ctrl+V, Cmd+V vb.)
|
|
66
|
+
if (!/[0-9]/.test(key) && key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
|
86
67
|
event.preventDefault();
|
|
87
|
-
|
|
88
|
-
_inputs.current[index - 1]?.focus();
|
|
89
|
-
setTimeout(() => _inputs.current[index - 1]?.select(), 0);
|
|
68
|
+
return;
|
|
90
69
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
70
|
+
// Eğer tek bir rakam basıldıysa ve input seçiliyse (üzerine yazma mantığı)
|
|
71
|
+
if (/[0-9]/.test(key) && key.length === 1) {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
const newValues = [...otpValues];
|
|
74
|
+
newValues[index] = key; // Değeri set et (seçili olduğu için direkt üzerine yazar)
|
|
75
|
+
triggerChange(newValues, event);
|
|
76
|
+
// Son kutuda değilsek bir sonrakine geç ve seç
|
|
77
|
+
if (index < character - 1) {
|
|
78
|
+
const nextInput = _inputs.current[index + 1];
|
|
79
|
+
nextInput?.focus();
|
|
80
|
+
setTimeout(() => nextInput?.select(), 0);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Son kutudaysa sadece seçili bırak ki tekrar basıldığında üzerine yazabilsin
|
|
84
|
+
setTimeout(() => currentInput?.select(), 0);
|
|
85
|
+
}
|
|
94
86
|
}
|
|
95
|
-
}, [character]);
|
|
87
|
+
}, [character, otpValues, attributes.disabled, onChange, attributes.name]);
|
|
88
|
+
const handlePaste = useCallback((index) => (event) => {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
if (attributes.disabled)
|
|
91
|
+
return;
|
|
92
|
+
const pastedData = event.clipboardData.getData("text").trim();
|
|
93
|
+
if (!/^\d+$/.test(pastedData))
|
|
94
|
+
return; // Sadece rakam ise kabul et
|
|
95
|
+
const digits = pastedData.split("").slice(0, character - index);
|
|
96
|
+
const newValues = [...otpValues];
|
|
97
|
+
digits.forEach((digit, i) => {
|
|
98
|
+
if (index + i < character) {
|
|
99
|
+
newValues[index + i] = digit;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
triggerChange(newValues, event);
|
|
103
|
+
// Yapıştırılan son karaktere veya son input'a focus at
|
|
104
|
+
const focusIndex = Math.min(index + digits.length, character - 1);
|
|
105
|
+
const targetInput = _inputs.current[focusIndex];
|
|
106
|
+
targetInput?.focus();
|
|
107
|
+
setTimeout(() => targetInput?.select(), 0);
|
|
108
|
+
}, [character, otpValues, attributes.disabled]);
|
|
96
109
|
const handleClick = useCallback((event) => {
|
|
97
|
-
|
|
98
|
-
if (document.activeElement === input)
|
|
99
|
-
input.select();
|
|
110
|
+
event.currentTarget.select();
|
|
100
111
|
}, []);
|
|
112
|
+
// useEffects
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
setOtpValues(Array(character).fill(""));
|
|
115
|
+
}, [character]);
|
|
101
116
|
return (React.createElement("div", { className: "ar-input-otp-wrapper" }, Array.from({ length: character }, (_, index) => (React.createElement("span", { key: index },
|
|
102
117
|
React.createElement(Input, { ref: (el) => {
|
|
103
118
|
_inputs.current[index] = el;
|
|
104
|
-
}, ...attributes, value:
|
|
119
|
+
}, ...attributes, value: otpValues[index], onChange: () => { }, onKeyDown: handleKeyDown(index), onPaste: handlePaste(index), onFocus: (event) => event.target.select(), onClick: handleClick, size: 1, maxLength: 1, placeholder: undefined, autoFocus: index === 0, autoComplete: "off" }))))));
|
|
105
120
|
};
|
|
106
121
|
Otp.displayName = "Input.Otp";
|
|
107
122
|
export default Otp;
|
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
import { IBorder, IColors, IIcon, ISize, IUpperCase, IValidation, IVariant } from "../../../libs/types/IGlobalProps";
|
|
2
2
|
import { Color } from "../../../libs/types";
|
|
3
3
|
interface IProps extends IVariant, IColors, IBorder, IIcon, ISize, IUpperCase, IValidation, Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "size" | "color"> {
|
|
4
|
-
/**
|
|
5
|
-
* Bileşenin başlığı veya etiket metnidir.
|
|
6
|
-
*
|
|
7
|
-
* Genellikle input, buton gibi öğelerin ne amaçla kullanıldığını belirtmek için görüntülenir.
|
|
8
|
-
*
|
|
9
|
-
* Örneğin;
|
|
10
|
-
*
|
|
11
|
-
* ```jsx
|
|
12
|
-
* <Radio label="Kullanıcı Adı" />
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
4
|
label?: string;
|
|
16
|
-
/**
|
|
17
|
-
* Bileşenin izlenebilir bir durum göstergesi (trace) olup olmadığını belirtir.
|
|
18
|
-
*
|
|
19
|
-
* - `color`: İzleme durumunu belirtmek için kullanılır. `Status` tipiyle tanımlanır (örneğin "success", "error", "warning" gibi).
|
|
20
|
-
*
|
|
21
|
-
* Örneğin;
|
|
22
|
-
*
|
|
23
|
-
* ```jsx
|
|
24
|
-
* <Radio trace={{ color: "success" }} />
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
5
|
trace?: {
|
|
28
6
|
color: Color;
|
|
29
7
|
};
|
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import { IBorder, IColors, IDisabled, IIcon, ISize, IUpperCase, IValidation, IVariant } from "../../../libs/types/IGlobalProps";
|
|
2
2
|
interface IProps extends IVariant, IColors, IBorder, IIcon, ISize, IUpperCase, IValidation, IDisabled, Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "size" | "color"> {
|
|
3
|
-
/**
|
|
4
|
-
* Bileşenin başlığı veya etiket metnidir.
|
|
5
|
-
*
|
|
6
|
-
* Genellikle input, buton gibi öğelerin ne amaçla kullanıldığını belirtmek için görüntülenir.
|
|
7
|
-
*
|
|
8
|
-
* Örneğin;
|
|
9
|
-
*
|
|
10
|
-
* ```jsx
|
|
11
|
-
* <Switch label="Kullanıcı Adı" />
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
3
|
label?: string;
|
|
15
4
|
}
|
|
16
5
|
export default IProps;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ar-design",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.64",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"react",
|
|
33
33
|
"next",
|
|
34
34
|
"ui",
|
|
35
|
-
"
|
|
35
|
+
"design"
|
|
36
36
|
],
|
|
37
37
|
"author": "Kaan ÇETİN",
|
|
38
38
|
"license": "MIT",
|