ar-design 0.1.29 → 0.1.30

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.
@@ -1,8 +1,12 @@
1
1
  .ar-modal-wrapper {
2
2
  position: absolute;
3
3
  inset: 0;
4
+ }
5
+ .ar-modal-wrapper > .ar-modal-bg {
6
+ position: fixed;
7
+ inset: 0;
4
8
  background-color: rgba(var(--black-rgb), 0.5);
5
- backdrop-filter: blur(5px);
9
+ backdrop-filter: blur(10px);
6
10
  }
7
11
 
8
12
  /* #region Open or Close */
@@ -20,6 +20,11 @@
20
20
  box-sizing: border-box;
21
21
  transition: background 250ms, border 250ms, box-shadow 250ms ease-in-out;
22
22
  }
23
+ .ar-input-wrapper > .ar-input > .validation {
24
+ color: var(--danger);
25
+ font-size: 0.8rem;
26
+ font-weight: 600;
27
+ }
23
28
 
24
29
  /* Core Css */
25
30
  @import url("./core/icon.css");
@@ -56,6 +56,14 @@
56
56
  line-height: 0.7rem;
57
57
  cursor: pointer;
58
58
  }
59
+ .ar-select-wrapper > .ar-select > .button-clear:is(.opened) {
60
+ visibility: visible;
61
+ opacity: 1;
62
+ }
63
+ .ar-select-wrapper > .ar-select > .button-clear:is(.closed) {
64
+ visibility: hidden;
65
+ opacity: 0;
66
+ }
59
67
  .ar-select-wrapper > .ar-select > .button-clear::before {
60
68
  content: "x";
61
69
  color: var(--white);
@@ -2,7 +2,7 @@ import React from "react";
2
2
  import IProps from "./IProps";
3
3
  import "../../../assets/css/components/data-display/table/table.css";
4
4
  declare const Table: {
5
- <T extends object>({ children, data, columns, selections, pagination, config, }: IProps<T>): React.JSX.Element;
5
+ <T extends object>({ children, data, columns, selections, pagination, config }: IProps<T>): React.JSX.Element;
6
6
  Action: React.FC<{
7
7
  children: React.ReactElement<{
8
8
  children: React.ReactElement<import("../../form/button/IProps").default> | React.ReactElement<import("../../form/button/IProps").default>[];
@@ -5,7 +5,7 @@ import Checkbox from "../../form/checkbox";
5
5
  import Actions from "./Actions";
6
6
  import Input from "../../form/input";
7
7
  import Pagination from "../../navigation/pagination";
8
- const Table = function ({ children, data, columns, selections, pagination, config, }) {
8
+ const Table = function ({ children, data, columns, selections, pagination, config }) {
9
9
  // refs
10
10
  let _dataLength = useRef(0);
11
11
  const _tableWrapper = useRef(null);
@@ -185,9 +185,7 @@ const Table = function ({ children, data, columns, selections, pagination, confi
185
185
  else if (typeof c.key === "object") {
186
186
  const _item = item[c.key.field];
187
187
  if (_item && typeof _item === "object") {
188
- render = c.render
189
- ? c.render(item)
190
- : _item[c.key.nestedKey];
188
+ render = c.render ? c.render(item) : _item[c.key.nestedKey];
191
189
  }
192
190
  }
193
191
  // Diğer durumlarda `null` döndür
@@ -13,11 +13,10 @@ const Modal = ({ children, open, title, size = "normal", footer }) => {
13
13
  else
14
14
  _modalWrapperClassName.push("closed");
15
15
  // methods
16
- const handleClickOutSide = (event) => {
17
- const target = event.target;
18
- if (_arModal.current && !_arModal.current.contains(target))
19
- open.set(false);
20
- };
16
+ // const handleClickOutSide = (event: MouseEvent) => {
17
+ // const target = event.target as HTMLElement;
18
+ // if (_arModal.current && !_arModal.current.contains(target)) open.set(false);
19
+ // };
21
20
  const handleKeys = (event) => {
22
21
  const key = event.key;
23
22
  if (key === "Escape")
@@ -26,16 +25,22 @@ const Modal = ({ children, open, title, size = "normal", footer }) => {
26
25
  // useEffects
27
26
  useEffect(() => {
28
27
  if (open.get) {
29
- document.addEventListener("click", handleClickOutSide);
28
+ // document.addEventListener("click", handleClickOutSide);
30
29
  document.addEventListener("keydown", handleKeys);
31
30
  // Dinleyicileri kaldır.
32
31
  return () => {
33
- document.removeEventListener("click", handleClickOutSide);
32
+ // document.removeEventListener("click", handleClickOutSide);
34
33
  document.removeEventListener("keydown", handleKeys);
35
34
  };
36
35
  }
37
36
  }, [open.get]);
38
37
  return (React.createElement("div", { className: _modalWrapperClassName.map((c) => c).join(" ") },
38
+ React.createElement("div", { className: "ar-modal-bg", onMouseDown: (event) => {
39
+ event.stopPropagation();
40
+ const target = event.target;
41
+ if (_arModal.current && !_arModal.current.contains(target))
42
+ open.set(false);
43
+ } }),
39
44
  React.createElement("div", { ref: _arModal, className: _modalClassName.map((c) => c).join(" "), role: "dialog" },
40
45
  React.createElement("div", { className: "header" },
41
46
  React.createElement(Title, { Level: "h3" }, title),
@@ -9,5 +9,9 @@ interface IProps extends Omit<IGlobalProps, "children" | "disabled">, Omit<React
9
9
  before?: string | number;
10
10
  after?: string | number;
11
11
  };
12
+ validation?: {
13
+ text: string | string[] | React.JSX.Element[] | null;
14
+ scrollTo?: boolean;
15
+ };
12
16
  }
13
17
  export default IProps;
@@ -3,13 +3,13 @@ import React, { forwardRef } from "react";
3
3
  import "../../../assets/css/components/form/input/input.css";
4
4
  import Button from "../button";
5
5
  import Utils from "../../../libs/infrastructure/shared/Utils";
6
- const Input = forwardRef(({ variant = "outlined", status = "light", size = "normal", icon, border = { radius: "sm" }, button, addon, ...attributes }, ref) => {
6
+ const Input = forwardRef(({ variant = "outlined", status = "light", size = "normal", icon, border = { radius: "sm" }, button, addon, validation, ...attributes }, ref) => {
7
7
  // variables
8
8
  const _wrapperClassName = ["ar-input-wrapper"];
9
9
  const _addonBeforeClassName = ["addon-before"];
10
10
  const _addonAfterClassName = ["addon-after"];
11
11
  const _inputClassName = [];
12
- _inputClassName.push(...Utils.GetClassName(variant, status, border, size, icon, attributes.className));
12
+ _inputClassName.push(...Utils.GetClassName(variant, validation?.text ? "danger" : status, border, size, icon, attributes.className));
13
13
  // addon className
14
14
  if (addon) {
15
15
  _wrapperClassName.push("addon");
@@ -21,7 +21,7 @@ const Input = forwardRef(({ variant = "outlined", status = "light", size = "norm
21
21
  _addonAfterClassName.push(`border-radius-${border.radius}`);
22
22
  }
23
23
  return (React.createElement("div", { className: _wrapperClassName.map((c) => c).join(" ") },
24
- addon?.before && (React.createElement("span", { className: _addonBeforeClassName.map((c) => c).join(" ") }, addon?.before)),
24
+ addon?.before && React.createElement("span", { className: _addonBeforeClassName.map((c) => c).join(" ") }, addon?.before),
25
25
  React.createElement("div", { className: "ar-input" },
26
26
  icon?.element && React.createElement("span", { className: "icon-element" }, icon.element),
27
27
  React.createElement("input", { ref: ref, ...attributes, size: 20, className: _inputClassName.map((c) => c).join(" "), onChange: (event) => {
@@ -40,8 +40,9 @@ const Input = forwardRef(({ variant = "outlined", status = "light", size = "norm
40
40
  });
41
41
  }
42
42
  })();
43
- } })),
44
- addon?.after && (React.createElement("span", { className: _addonAfterClassName.map((c) => c).join(" ") }, addon?.after)),
43
+ } }),
44
+ validation?.text && React.createElement("span", { className: "validation" }, validation.text)),
45
+ addon?.after && React.createElement("span", { className: _addonAfterClassName.map((c) => c).join(" ") }, addon?.after),
45
46
  button && (React.createElement(Button, { ...button, status: status, border: { radius: border.radius }, disabled: attributes.disabled }))));
46
47
  });
47
48
  Input.displayName = "Input";
@@ -222,8 +222,10 @@ const Select = ({ variant = "outlined", status, border = { radius: "sm" }, optio
222
222
  // Arama yapmak için kullanılan state bu kısımda dolduruluyor.
223
223
  setSearchText(event.currentTarget.value);
224
224
  }, placeholder: attributes.placeholder, disabled: attributes.disabled })),
225
- !attributes.disabled &&
226
- (Object.keys(selection || {}).length > 0 || (multiple && selections.length > 0)) && (React.createElement("span", { className: "button-clear", onClick: () => {
225
+ React.createElement("span", { className: `button-clear ${!attributes.disabled && (Object.keys(selection || {}).length > 0 || (multiple && selections.length > 0))
226
+ ? "opened"
227
+ : "closed"}`, onClick: (event) => {
228
+ event.stopPropagation();
227
229
  // Multiple
228
230
  if (multiple) {
229
231
  if (_searchField.current)
@@ -239,7 +241,7 @@ const Select = ({ variant = "outlined", status, border = { radius: "sm" }, optio
239
241
  setSelection(undefined);
240
242
  onChange(undefined);
241
243
  }
242
- } })),
244
+ } }),
243
245
  React.createElement("span", { className: `angel-down ${optionsOpen ? "opened" : "closed"}`, onClick: (event) => {
244
246
  event.stopPropagation();
245
247
  setOptionsOpen((x) => !x);
@@ -1,20 +1,21 @@
1
1
  "use client";
2
- import React, { useContext, useEffect, useRef, useState } from "react";
2
+ import React, { useContext, useEffect, useState } from "react";
3
3
  import "../../../assets/css/components/navigation/pagination/pagination.css";
4
4
  import { ConfigContext } from "../../../libs/core/application/contexts/Config";
5
5
  const Pagination = ({ defaultCurrent = 1, totalRecords, perPage, onChange }) => {
6
6
  // context
7
7
  const { config } = useContext(ConfigContext);
8
- // refs
9
- const _totalPageCount = useRef(Math.ceil(totalRecords / (perPage ?? config.perPage))).current;
10
8
  // states
11
9
  const [pages, setPages] = useState([]);
12
10
  const [currentPage, setCurrentPage] = useState(defaultCurrent);
11
+ const [totalPageCount, setTotalPageCount] = useState(0);
13
12
  // useEffect
14
13
  useEffect(() => {
15
14
  if (totalRecords === 0)
16
15
  return;
17
16
  const liItems = [];
17
+ const _totalPageCount = Math.ceil(totalRecords / (perPage ?? config.perPage));
18
+ setTotalPageCount(_totalPageCount);
18
19
  // Başlangıç ve bitiş aralığını hesapla.
19
20
  const startPage = Math.max(1, currentPage - 1);
20
21
  const endPage = Math.min(_totalPageCount, currentPage + 1);
@@ -58,20 +59,20 @@ const Pagination = ({ defaultCurrent = 1, totalRecords, perPage, onChange }) =>
58
59
  } },
59
60
  React.createElement("span", null, "‹")),
60
61
  pages,
61
- React.createElement("li", { className: _totalPageCount === currentPage ? "passive" : "", onClick: () => {
62
- if (_totalPageCount === currentPage)
62
+ React.createElement("li", { className: totalPageCount === currentPage ? "passive" : "", onClick: () => {
63
+ if (totalPageCount === currentPage)
63
64
  return;
64
65
  setCurrentPage((prev) => {
65
- if (prev === _totalPageCount)
66
+ if (prev === totalPageCount)
66
67
  return prev;
67
68
  return (prev += 1);
68
69
  });
69
70
  } },
70
71
  React.createElement("span", null, "›")),
71
- React.createElement("li", { className: _totalPageCount === currentPage ? "passive" : "", onClick: () => {
72
- if (_totalPageCount === currentPage)
72
+ React.createElement("li", { className: totalPageCount === currentPage ? "passive" : "", onClick: () => {
73
+ if (totalPageCount === currentPage)
73
74
  return;
74
- setCurrentPage(_totalPageCount);
75
+ setCurrentPage(totalPageCount);
75
76
  } },
76
77
  React.createElement("span", null, "»")))));
77
78
  };
@@ -1,4 +1,5 @@
1
1
  import { Status } from "../contexts/Notification";
2
+ import { ValidationProperties } from "../../../types";
2
3
  export declare const useLayout: () => {
3
4
  config: {
4
5
  layout: {
@@ -32,9 +33,24 @@ export declare const useLayout: () => {
32
33
  }>>;
33
34
  };
34
35
  export declare const useNotification: () => {
35
- notification: ({ title, message, status, }: {
36
+ notification: ({ title, message, status }: {
36
37
  title: string;
37
38
  message?: string;
38
39
  status: Status;
39
40
  }) => void;
40
41
  };
42
+ type Error = {
43
+ [key: string]: string;
44
+ type: string;
45
+ }[];
46
+ export declare const useValidation: <TData extends object>(data: TData, params: ValidationProperties<TData>[]) => {
47
+ submit: boolean;
48
+ setSubmit: import("react").Dispatch<import("react").SetStateAction<boolean>>;
49
+ success: boolean;
50
+ setSuccess: import("react").Dispatch<import("react").SetStateAction<boolean>>;
51
+ message: string | null;
52
+ setMessage: import("react").Dispatch<import("react").SetStateAction<string | null>>;
53
+ errors: Error;
54
+ showErrors: (errors: Error, field: string) => string[] | null;
55
+ };
56
+ export {};
@@ -1,6 +1,7 @@
1
- import { useContext } from "react";
1
+ import { useContext, useEffect, useState } from "react";
2
2
  import { ConfigContext } from "../contexts/Config";
3
3
  import { NotificationContext } from "../contexts/Notification";
4
+ import Utils from "../../../infrastructure/shared/Utils";
4
5
  export const useLayout = () => {
5
6
  const context = useContext(ConfigContext);
6
7
  if (!context) {
@@ -12,7 +13,7 @@ export const useNotification = () => {
12
13
  // contexts
13
14
  const { setTitle, setMessage, setStatus, setTrigger } = useContext(NotificationContext);
14
15
  // methods
15
- const notification = ({ title, message, status, }) => {
16
+ const notification = ({ title, message, status }) => {
16
17
  setTitle && setTitle(title);
17
18
  setMessage && setMessage(message ?? "");
18
19
  setStatus && setStatus(status);
@@ -20,3 +21,67 @@ export const useNotification = () => {
20
21
  };
21
22
  return { notification };
22
23
  };
24
+ export const useValidation = function (data, params) {
25
+ // useStates
26
+ const [submit, setSubmit] = useState(false);
27
+ const [success, setSuccess] = useState(true);
28
+ const [message, setMessage] = useState(null);
29
+ const [errors, setErrors] = useState([]);
30
+ // methods
31
+ const showErrors = (errors, field) => {
32
+ const _errors = errors.filter((error) => error[field]);
33
+ if (_errors.length === 0)
34
+ return null;
35
+ return _errors.map((error) => error[field]);
36
+ };
37
+ // useEffects
38
+ useEffect(() => {
39
+ if (!data || Object.keys(data).length === 0 || params.length === 0)
40
+ return;
41
+ setErrors([]);
42
+ params.forEach((param) => {
43
+ const value = data[param.key];
44
+ param.shape?.forEach((s) => {
45
+ if (s.type === "required") {
46
+ !value ? setErrors((errors) => [...errors, { [param.key]: s.message, type: s.type }]) : null;
47
+ }
48
+ if (s.type === "minimum") {
49
+ value && value.length < s.value
50
+ ? setErrors((errors) => [
51
+ ...errors,
52
+ {
53
+ [param.key]: Utils.StringFormat(s.message, s.value, 4),
54
+ type: s.type,
55
+ },
56
+ ])
57
+ : null;
58
+ }
59
+ if (s.type === "maximum") {
60
+ value && value.length > s.value
61
+ ? setErrors((errors) => [
62
+ ...errors,
63
+ {
64
+ [param.key]: Utils.StringFormat(s.message, s.value),
65
+ type: s.type,
66
+ },
67
+ ])
68
+ : null;
69
+ }
70
+ if (s.type === "email") {
71
+ const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
72
+ !regex && value ? setErrors((errors) => [...errors, { [param.key]: s.message, type: s.type }]) : null;
73
+ }
74
+ });
75
+ });
76
+ }, [data]);
77
+ return {
78
+ submit,
79
+ setSubmit,
80
+ success,
81
+ setSuccess,
82
+ message,
83
+ setMessage,
84
+ errors,
85
+ showErrors,
86
+ };
87
+ };
@@ -1,6 +1,7 @@
1
1
  import { Border, Icon, Sizes, Status, Variants } from "../../types";
2
2
  declare class Utils {
3
3
  GetClassName: (variant?: Variants, status?: Status, border?: Border, size?: Sizes, icon?: Icon, className?: string) => string[];
4
+ StringFormat: (value: string, ...args: any[]) => string;
4
5
  }
5
6
  declare const _default: Utils;
6
7
  export default _default;
@@ -11,5 +11,13 @@ class Utils {
11
11
  classNames.push(className);
12
12
  return classNames;
13
13
  };
14
+ StringFormat = (value, ...args) => {
15
+ if (args[0].length === 0)
16
+ return value;
17
+ return value.replace(/{(\d+)}/g, (match, number) => {
18
+ const index = parseInt(number, 10);
19
+ return typeof args[index] !== "undefined" ? args[index] : match;
20
+ });
21
+ };
14
22
  }
15
23
  export default new Utils();
@@ -39,3 +39,11 @@ export type StepProps = {
39
39
  title: string;
40
40
  content: React.ReactNode;
41
41
  };
42
+ export type ValidationProperties<T> = {
43
+ key: keyof T;
44
+ shape?: {
45
+ type: "required" | "minimum" | "maximum" | "email";
46
+ value?: string | number;
47
+ message: string;
48
+ }[];
49
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ar-design",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",