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.
Files changed (30) hide show
  1. package/dist/assets/css/components/data-display/card/styles.css +2 -2
  2. package/dist/assets/css/components/data-display/dnd/styles.css +3 -3
  3. package/dist/assets/css/components/data-display/syntax-highlighter/syntax-highlighter.css +2 -2
  4. package/dist/assets/css/components/feedback/alert/styles.css +2 -2
  5. package/dist/assets/css/components/feedback/drawer/styles.css +3 -3
  6. package/dist/assets/css/components/feedback/modal/styles.css +15 -11
  7. package/dist/assets/css/components/feedback/progress/progress.css +3 -3
  8. package/dist/assets/css/components/form/button/styles.css +10 -7
  9. package/dist/assets/css/components/form/checkbox/checkbox.css +2 -2
  10. package/dist/assets/css/components/form/date-picker/date-picker.css +10 -10
  11. package/dist/assets/css/components/form/input/styles.css +15 -12
  12. package/dist/assets/css/components/form/radio/radio.css +2 -2
  13. package/dist/assets/css/components/form/select/styles.css +2 -2
  14. package/dist/assets/css/components/form/switch/styles.css +7 -3
  15. package/dist/assets/css/components/layout/layout.css +10 -10
  16. package/dist/assets/css/components/navigation/steps/styles.css +5 -3
  17. package/dist/assets/css/core/ar-core.css +25 -20
  18. package/dist/assets/css/core/utils.css +3 -0
  19. package/dist/components/data-display/table/FilterPopup.js +8 -12
  20. package/dist/components/data-display/table/PropertiesPopup.js +10 -19
  21. package/dist/components/data-display/table/THeadCell.js +9 -8
  22. package/dist/components/data-display/table/body/TBody.js +53 -37
  23. package/dist/components/data-display/table/index.js +68 -175
  24. package/dist/components/feedback/popover/index.js +6 -0
  25. package/dist/components/feedback/tooltip/index.js +63 -16
  26. package/dist/components/form/date-picker/Props.d.ts +0 -1
  27. package/dist/components/form/input/otp/Otp.js +94 -79
  28. package/dist/components/form/radio/IProps.d.ts +0 -22
  29. package/dist/components/form/switch/IProps.d.ts +0 -11
  30. 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 screenCenterX = windowWidth / 2;
26
+ const windowHeight = window.innerHeight;
21
27
  const childRect = child.getBoundingClientRect();
22
28
  const tooltipRect = tooltip.getBoundingClientRect();
23
- const isOnRight = childRect.left > screenCenterX;
24
- if (direction === "top" || direction === "bottom") {
25
- if (isOnRight && tooltipRect.right > windowWidth - 10) {
26
- direction = "left";
27
- }
28
- else if (!isOnRight && tooltipRect.left < 10) {
29
- direction = "right";
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 (direction) {
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
- setDirection(direction);
55
- }, []);
56
- //useEffects
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,6 +1,5 @@
1
1
  import { IBorder, IColors, IStatus, IValidation, IVariant } from "../../../libs/types/IGlobalProps";
2
2
  type Props = {
3
- label?: string;
4
3
  onChange: (value: string) => void;
5
4
  config?: {
6
5
  locale?: Intl.LocalesArgument;
@@ -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
- const _isPasteCombo = useRef(false);
8
- const _value = useRef({});
7
+ // states
8
+ const [otpValues, setOtpValues] = useState(() => Array(character).fill(""));
9
9
  // methods
10
- const handleInput = useCallback((index) => (event) => {
11
- if (attributes.disabled)
12
- return;
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: Object.keys(_value.current)
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
- }, [onChange, attributes.name, attributes.disabled]);
38
- const handleKeyUp = useCallback((index) => (event) => {
39
- const input = event.currentTarget;
40
- const { value } = input;
41
- const beforeInput = _inputs.current[index];
42
- // referans
43
- const beforeInputValue = beforeInput.value;
44
- if (beforeInputValue.length > 1) {
45
- let i = 0;
46
- const chars = beforeInputValue.split("");
47
- const interval = setInterval(() => {
48
- const input = _inputs.current[i];
49
- if (input) {
50
- input.value = chars[i];
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
- const lastChar = value.slice(-1);
72
- event.currentTarget.value = lastChar;
73
- if (event.key === "Backspace" && value.length === 0) {
74
- _inputs.current[index - 1]?.focus();
75
- }
76
- }, []);
77
- const handleKeyDown = useCallback((index) => (event) => {
78
- _isPasteCombo.current = (event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "v";
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
- if (index === 0 && (event.key === "ArrowDown" || event.key === "ArrowLeft"))
82
- event.preventDefault();
83
- if (index + 1 >= character && (event.key === "ArrowUp" || event.key === "ArrowRight"))
46
+ }
47
+ // Backspace (Silme) İşlemi
48
+ if (key === "Backspace") {
84
49
  event.preventDefault();
85
- if (!/[0-9]/.test(event.key) && event.key.length === 1)
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
- if (event.key === "ArrowDown" || event.key === "ArrowLeft") {
88
- _inputs.current[index - 1]?.focus();
89
- setTimeout(() => _inputs.current[index - 1]?.select(), 0);
68
+ return;
90
69
  }
91
- else if (event.key === "ArrowUp" || event.key === "ArrowRight") {
92
- _inputs.current[index + 1]?.focus();
93
- setTimeout(() => _inputs.current[index + 1]?.select(), 0);
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
- const input = event.currentTarget;
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: _value.current[index] ?? "", onInput: handleInput(index), onKeyUp: handleKeyUp(index), onKeyDown: handleKeyDown(index), onFocus: (event) => event.target.select(), onClick: handleClick, size: 1, placeholder: undefined, autoFocus: index === 0, autoComplete: "off" }))))));
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.63",
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
- "desing"
35
+ "design"
36
36
  ],
37
37
  "author": "Kaan ÇETİN",
38
38
  "license": "MIT",