ar-design 0.4.24 → 0.4.26

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.
@@ -21,6 +21,7 @@ export type SearchedParam = {
21
21
  [key: string]: FilterValue | FilterValue[];
22
22
  };
23
23
  export type Config<T> = {
24
+ locale?: string;
24
25
  isServerSide?: boolean;
25
26
  isProperties?: boolean;
26
27
  isSearchable?: boolean;
@@ -1,11 +1,13 @@
1
1
  import React from "react";
2
2
  import { Errors, TableColumnType } from "../../../../libs/types";
3
+ import { Config } from "../IProps";
3
4
  interface IProps<T> {
4
5
  c: TableColumnType<T>;
5
6
  item: T;
6
7
  trackByValue: string;
7
8
  onEditable: (item: T, trackByValue: string) => void;
8
9
  validation?: Errors<T>;
10
+ config: Config<T>;
9
11
  }
10
- declare const Editable: <T>({ c, item, trackByValue, onEditable, validation }: IProps<T>) => React.JSX.Element | null;
12
+ declare const Editable: <T>({ c, item, trackByValue, onEditable, validation, config }: IProps<T>) => React.JSX.Element | null;
11
13
  export default Editable;
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react";
3
3
  import Input from "../../../form/input";
4
4
  import DatePicker from "../../../form/date-picker";
5
5
  import Select from "../../../form/select";
6
- const Editable = function ({ c, item, trackByValue, onEditable, validation }) {
6
+ const Editable = function ({ c, item, trackByValue, onEditable, validation, config }) {
7
7
  // variables
8
8
  const key = c.key;
9
9
  const itemValue = item[c.key];
@@ -29,13 +29,13 @@ const Editable = function ({ c, item, trackByValue, onEditable, validation }) {
29
29
  const { value } = event.target;
30
30
  setValue(value);
31
31
  onEditable({ ...item, [key]: value }, trackByValue);
32
- }, validation: { text: _vText } }));
32
+ }, validation: { text: _vText }, locale: config.locale }));
33
33
  case "input-formatted-decimal":
34
34
  return (React.createElement(Input.FormattedDecimal, { variant: "borderless", name: c.key, value: _value, onChange: (event) => {
35
35
  const { value } = event.target;
36
36
  setValue(value);
37
37
  onEditable({ ...item, [key]: value }, trackByValue);
38
- }, validation: { text: _vText } }));
38
+ }, validation: { text: _vText }, locale: config.locale }));
39
39
  case "date-picker":
40
40
  return (React.createElement(DatePicker, { variant: "borderless", value: _value, onChange: (value) => {
41
41
  setValue(value);
@@ -1,15 +1,23 @@
1
- import React from "react";
1
+ import React, { Dispatch, SetStateAction } from "react";
2
2
  import { TableColumnType } from "../../../../libs/types";
3
3
  import { Config } from "../IProps";
4
4
  interface IProps<T> {
5
5
  data: T[];
6
6
  columns: TableColumnType<T>[];
7
+ refs: {
8
+ _checkboxItems: React.MutableRefObject<(HTMLInputElement | null)[]>;
9
+ _selectionItems: React.MutableRefObject<T[]>;
10
+ };
7
11
  states: {
12
+ setSelectAll: {
13
+ get: boolean;
14
+ set: Dispatch<SetStateAction<boolean>>;
15
+ };
8
16
  showSubitems: {
9
17
  get: {
10
18
  [key: string]: boolean;
11
19
  };
12
- set: React.Dispatch<React.SetStateAction<{
20
+ set: Dispatch<React.SetStateAction<{
13
21
  [key: string]: boolean;
14
22
  }>>;
15
23
  };
@@ -23,6 +31,6 @@ interface IProps<T> {
23
31
  };
24
32
  config: Config<T>;
25
33
  }
26
- declare function TBody<T extends object>({ data, columns, methods, states, config }: IProps<T>): React.JSX.Element | React.JSX.Element[];
34
+ declare function TBody<T extends object>({ data, columns, refs, methods, states, config }: IProps<T>): React.JSX.Element | React.JSX.Element[];
27
35
  declare const _default: typeof TBody;
28
36
  export default _default;
@@ -2,14 +2,12 @@ import React, { Fragment, memo, useEffect, useRef, useState } from "react";
2
2
  import { ARIcon } from "../../../icons";
3
3
  import Checkbox from "../../../form/checkbox";
4
4
  import Editable from "./Editable";
5
- function TBody({ data, columns, methods, states, config }) {
5
+ function TBody({ data, columns, refs, methods, states, config }) {
6
6
  // refs
7
+ const _hasMeasured = useRef(false);
7
8
  const _tBodyTR = useRef([]);
8
- const _checkboxItems = useRef([]);
9
- // refs -> Selection
10
- const _selectionItems = useRef([]);
11
9
  // states
12
- const [_, setTriggerForRender] = useState(false);
10
+ const [triggerForRender, setTriggerForRender] = useState(false);
13
11
  const [rowHeights, setRowHeights] = useState([]);
14
12
  // variables
15
13
  const _subrowSelector = config.subrow?.selector ?? "subitems";
@@ -22,17 +20,17 @@ function TBody({ data, columns, methods, states, config }) {
22
20
  _tBodyTR.current[index] = element;
23
21
  }, ...(methods.rowBackgroundColor ? { style: { backgroundColor: methods.rowBackgroundColor(item) } } : {}), ...(methods.onDnD && data.length > 1 ? { className: "draggable", draggable: true } : {}) },
24
22
  methods.selections && (React.createElement("td", { className: "flex justify-content-center sticky-left", "data-sticky-position": "left" },
25
- React.createElement(Checkbox, { key: Date.now(), ref: (element) => (_checkboxItems.current[index] = element), variant: "filled", color: "green", checked: _selectionItems.current.some((selectionItem) => methods.trackBy?.(selectionItem) === methods.trackBy?.(item)), onChange: (event) => {
23
+ React.createElement(Checkbox, { key: Date.now(), ref: (element) => (refs._checkboxItems.current[index] = element), variant: "filled", color: "green", checked: refs._selectionItems.current.some((selectionItem) => methods.trackBy?.(selectionItem) === methods.trackBy?.(item)), onChange: (event) => {
26
24
  const key = methods.trackBy?.(item);
27
25
  if (event.target.checked) {
28
- if (!_selectionItems.current.some((_item) => methods.trackBy?.(_item) === key)) {
29
- _selectionItems.current = [..._selectionItems.current, item];
26
+ if (!refs._selectionItems.current.some((_item) => methods.trackBy?.(_item) === key)) {
27
+ refs._selectionItems.current = [...refs._selectionItems.current, item];
30
28
  }
31
29
  }
32
30
  else {
33
- _selectionItems.current = _selectionItems.current.filter((_item) => methods.trackBy?.(_item) !== key);
31
+ refs._selectionItems.current = refs._selectionItems.current.filter((_item) => methods.trackBy?.(_item) !== key);
34
32
  }
35
- methods.selections?.(_selectionItems.current);
33
+ methods.selections?.(refs._selectionItems.current);
36
34
  setTriggerForRender((prev) => !prev);
37
35
  } }))),
38
36
  isHasSubitems && _subrowButton ? (React.createElement("td", null, item[_subrowSelector] && (React.createElement("div", { className: "subitem-open-button-wrapper" },
@@ -91,7 +89,7 @@ function TBody({ data, columns, methods, states, config }) {
91
89
  return (React.createElement("div", { key: `last-before-${i}`, style: { left: `${i + 0.65}rem` }, className: "last-before" }));
92
90
  }),
93
91
  React.createElement("div", { className: "before" }))),
94
- React.isValidElement(render) ? (render) : column.editable && methods.onEditable ? (React.createElement(Editable, { c: column, item: item, trackByValue: methods.trackBy?.(item) ?? "", onEditable: methods.onEditable, validation: config.validation })) : (React.createElement("span", null, render)),
92
+ React.isValidElement(render) ? (render) : column.editable && methods.onEditable ? (React.createElement(Editable, { c: column, item: item, trackByValue: methods.trackBy?.(item) ?? "", onEditable: methods.onEditable, validation: config.validation, config: config })) : (React.createElement("span", null, render)),
95
93
  config.isTreeView && cIndex === 0 && (React.createElement("div", { className: "after" },
96
94
  React.createElement("div", { className: "circle" }))))));
97
95
  };
@@ -131,9 +129,21 @@ function TBody({ data, columns, methods, states, config }) {
131
129
  };
132
130
  // useEffects
133
131
  useEffect(() => {
132
+ if (_hasMeasured.current)
133
+ return;
134
+ if (!data || data.length === 0)
135
+ return;
134
136
  const heights = _tBodyTR.current.map((el) => (el ? el.getBoundingClientRect().height : 0));
135
137
  setRowHeights(heights);
138
+ setTriggerForRender((prev) => !prev);
139
+ _hasMeasured.current = true;
136
140
  }, [data]);
141
+ useEffect(() => {
142
+ if (Array.isArray(refs._checkboxItems.current) && refs._checkboxItems.current.length > 0) {
143
+ const allChecked = refs._checkboxItems.current.every((item) => item?.checked === true);
144
+ states.setSelectAll.set(allChecked);
145
+ }
146
+ }, [triggerForRender]);
137
147
  return data.length > 0 ? (data.map((item, index) => React.createElement(React.Fragment, { key: index }, renderRow(item, index, 1)))) : (React.createElement("tr", null,
138
148
  React.createElement("td", { colSpan: columns.length || 1 },
139
149
  React.createElement("div", { className: "no-item" },
@@ -383,7 +383,7 @@ const Table = forwardRef(({ children, trackBy, title, description, data, columns
383
383
  _data = _data.slice(indexOfFirstRow, indexOfLastRow);
384
384
  }
385
385
  return _data;
386
- }, [data, searchedText, currentPage, selectedPerPage, sortConfig]);
386
+ }, [data, searchedText, currentPage, selectedPerPage, sortConfig, config.isServerSide]);
387
387
  // useEffects
388
388
  useEffect(() => {
389
389
  if (!previousSelections || previousSelections.length === 0) {
@@ -656,7 +656,10 @@ const Table = forwardRef(({ children, trackBy, title, description, data, columns
656
656
  } }))))));
657
657
  })))),
658
658
  React.createElement("tbody", { ref: _tBody },
659
- React.createElement(TBody, { data: getData, columns: columns, states: { showSubitems: { get: showSubitems, set: setShowSubitems } }, methods: {
659
+ React.createElement(TBody, { data: getData, columns: columns, refs: { _checkboxItems: _checkboxItems, _selectionItems: _selectionItems }, states: {
660
+ setSelectAll: { get: selectAll, set: setSelectAll },
661
+ showSubitems: { get: showSubitems, set: setShowSubitems },
662
+ }, methods: {
660
663
  trackBy: trackBy,
661
664
  selections: selections,
662
665
  onDnD: onDnD,
@@ -251,10 +251,8 @@ const DatePicker = ({ variant, color, onChange, config, validation, ...attribute
251
251
  attributes.placeholder && attributes.placeholder.length > 0 && (React.createElement("label", { ref: _placeholder },
252
252
  validation ? "* " : "",
253
253
  attributes.placeholder)),
254
- React.createElement("div", { className: "wrapper", ...(String(attributes.value).length > 0
255
- ? {
256
- style: {
257
- clipPath: `polygon(
254
+ React.createElement("div", { className: "wrapper", style: {
255
+ clipPath: `polygon(
258
256
  -15px 0,
259
257
  10px -5px,
260
258
  10px 5px,
@@ -264,9 +262,7 @@ const DatePicker = ({ variant, color, onChange, config, validation, ...attribute
264
262
  calc(100% + 5px) calc(100% + 5px),
265
263
  -5px calc(100% + 5px)
266
264
  )`,
267
- },
268
- }
269
- : {}) },
265
+ } },
270
266
  React.createElement(Input, { ref: _beginDate, variant: variant, color: color, ...attributes, value: DATE.ParseValue(String(attributes.value), config?.isClock), type: config?.isClock ? "datetime-local" : "date", onKeyDown: (event) => {
271
267
  if (event.code === "Space")
272
268
  event.preventDefault();
@@ -1,38 +1,50 @@
1
1
  "use client";
2
- import React, { useRef, useState, useEffect } from "react";
2
+ import React, { useRef, useState, useEffect, useMemo } from "react";
3
3
  import Input from "..";
4
- const Decimal = ({ variant, color, name, value, onChange, placeholder, validation, disabled }) => {
5
- // refs
4
+ const Decimal = ({ variant, color, name, value, onChange, placeholder, validation, disabled, locale = "tr-TR", }) => {
6
5
  const _input = useRef(null);
7
- // states
8
6
  const [_value, setValue] = useState("");
9
7
  // methods
8
+ const decimalSeparator = useMemo(() => {
9
+ const parts = new Intl.NumberFormat(locale).formatToParts(1.1);
10
+ return parts.find((p) => p.type === "decimal")?.value ?? ".";
11
+ }, [locale]);
10
12
  const handleChange = (event) => {
11
13
  let inputValue = event.target.value;
12
- inputValue = inputValue.replace(/[^0-9.]/g, "");
13
- const parts = inputValue.split(".");
14
+ // Locale’a göre izin verilen karakterler. (rakam, decimal, -)
15
+ const regex = new RegExp(`[^0-9\\${decimalSeparator}-]`, "g");
16
+ inputValue = inputValue.replace(regex, "");
17
+ // Sadece başta negatif işarete izin ver.
18
+ if (inputValue.includes("-")) {
19
+ inputValue = (inputValue.startsWith("-") ? "-" : "") + inputValue.replace(/-/g, "");
20
+ }
21
+ // Tek decimal separator’a izin ver.
22
+ const parts = inputValue.split(decimalSeparator);
14
23
  if (parts.length > 2) {
15
- inputValue = parts[0] + "." + parts.slice(1).join("");
24
+ inputValue = parts[0] + decimalSeparator + parts.slice(1).join("");
16
25
  }
17
26
  setValue(inputValue);
27
+ // Parent’a normalize edilmiş "." decimal gönder.
28
+ const normalized = inputValue.replace(decimalSeparator, ".");
18
29
  onChange?.({
19
30
  ...event,
20
31
  target: {
21
32
  ...event.target,
22
33
  name,
23
- value: inputValue,
34
+ value: normalized,
24
35
  },
25
36
  });
26
37
  };
27
38
  // useEffects
28
39
  useEffect(() => {
29
- if (value === undefined || value === null) {
40
+ if (value === undefined || value === null || value === "") {
30
41
  setValue("");
42
+ return;
31
43
  }
32
- else {
33
- setValue(String(value));
34
- }
35
- }, [value]);
44
+ const stringValue = String(value);
45
+ const localized = stringValue.replace(".", decimalSeparator);
46
+ setValue(localized);
47
+ }, [value, decimalSeparator]);
36
48
  return (React.createElement(Input, { ref: _input, name: name, variant: variant, color: color, type: "text", inputMode: "decimal", value: _value, onChange: (e) => {
37
49
  if (disabled)
38
50
  return;
@@ -3,5 +3,6 @@ interface IProps extends IVariant, IColors, IBorder, IUpperCase, IValidation, IP
3
3
  name: string;
4
4
  value: string | number | readonly string[] | undefined;
5
5
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
6
+ locale?: Intl.LocalesArgument;
6
7
  }
7
8
  export default IProps;
@@ -3,12 +3,16 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
3
3
  import Input from "..";
4
4
  import { NUMBER } from "../../../../libs/infrastructure/shared";
5
5
  const FormattedDecimal = ({ variant, color, name, value, onChange, locale = "tr-TR", digits, placeholder, validation, disabled, }) => {
6
- // refs
7
- // const _firstLoad = useRef<boolean>(false);
8
6
  const _input = useRef(null);
9
- // states
10
7
  const [_value, setValue] = useState("");
11
8
  // methods
9
+ const getSeparators = (locale) => {
10
+ const parts = new Intl.NumberFormat(locale).formatToParts(1000.1);
11
+ const group = parts.find((p) => p.type === "group")?.value ?? ",";
12
+ const decimal = parts.find((p) => p.type === "decimal")?.value ?? ".";
13
+ return { group, decimal };
14
+ };
15
+ const getFormatter = useMemo(() => NUMBER.Decimal(locale, digits), [locale, digits]);
12
16
  const handleClick = () => {
13
17
  const input = _input.current;
14
18
  if (!input)
@@ -33,48 +37,34 @@ const FormattedDecimal = ({ variant, color, name, value, onChange, locale = "tr-
33
37
  };
34
38
  const handleChange = (event) => {
35
39
  let { value } = event.target;
36
- // Temizle.
37
- const cleanedValue = (value = value.replace(/[^0-9,]/g, ""));
38
- // Numara olarak çevir.
39
- const normalized = parseCurrencySmart(value);
40
- // const isDecimals = cleanedValue.includes(",");
41
- const parsedDecimal = parseFloat(normalized);
42
- const newValue = isNaN(parsedDecimal) ? 0 : parsedDecimal;
43
- // Formatla ve Kullanıcı , (virgül) girdiyse kuruş göster.
44
- let formatted = newValue === 0 && cleanedValue === "" ? "" : getFormatter.format(newValue);
40
+ const { group, decimal } = getSeparators(locale);
41
+ // Locale’a göre izin verilen karakterleri temizle.
42
+ const regex = new RegExp(`[^0-9\\${group}\\${decimal}]`, "g");
43
+ value = value.replace(regex, "");
44
+ // Normalize et (decimal her zaman "." olacak şekilde)
45
+ let normalized = value.replace(new RegExp(`\\${group}`, "g"), "").replace(decimal, ".");
46
+ const parsed = parseFloat(normalized);
47
+ const numericValue = isNaN(parsed) ? 0 : parsed;
48
+ const formatted = value === "" ? "" : getFormatter.format(numericValue);
45
49
  setValue(formatted);
46
- onChange?.({ ...event, target: { ...event.target, name: name, value: normalized } });
47
- };
48
- const getFormatter = useMemo(() => NUMBER.Decimal(locale, digits), [digits]);
49
- const parseCurrencySmart = (input) => {
50
- if (input.includes(",") && input.includes(".")) {
51
- // Nokta binlik, virgül ondalık (tr-TR, de-DE gibi)
52
- return input.replace(/\./g, "").replace(",", ".");
53
- }
54
- else if (input.includes(",") && !input.includes(".")) {
55
- // Virgül ondalık, binlik yok (fr-FR gibi)
56
- return input.replace(",", ".");
57
- }
58
- else if (input.includes(".") && !input.includes(",")) {
59
- // Nokta ondalık, binlik yok veya US format
60
- return input.replace(/,/g, "");
61
- }
62
- else {
63
- // Hiçbiri yok, zaten sayı
64
- return input;
65
- }
50
+ onChange?.({
51
+ ...event,
52
+ target: {
53
+ ...event.target,
54
+ name,
55
+ value: normalized,
56
+ },
57
+ });
66
58
  };
67
59
  // useEffects
68
60
  useEffect(() => {
69
- // if (!_firstLoad.current && value !== undefined && value !== "") {
70
- // // const isDecimals = String(value).includes(".");
71
- // setValue(getFormatter.format(Number(value)));
72
- // _firstLoad.current = true;
73
- // }
61
+ if (value === undefined || value === null || value === "") {
62
+ setValue("");
63
+ return;
64
+ }
74
65
  setValue(getFormatter.format(Number(value)));
75
- }, [value]);
76
- return (React.createElement(Input, { ref: _input, name: name, variant: variant, color: color, value: _value ?? "", type: "text", inputMode: "decimal", onChange: (event) => {
77
- // Disabled gelmesi durumunda işlem yapmasına izin verme...
66
+ }, [value, getFormatter]);
67
+ return (React.createElement(Input, { ref: _input, name: name, variant: variant, color: color, value: _value, type: "text", inputMode: "decimal", onChange: (event) => {
78
68
  if (disabled)
79
69
  return;
80
70
  handleChange(event);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ar-design",
3
- "version": "0.4.24",
3
+ "version": "0.4.26",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",