naria-ui 0.1.36 → 0.1.37

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.
@@ -0,0 +1,16 @@
1
+ import React, {FC} from "react";
2
+
3
+ export interface props extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
4
+ type?: "button" | "submit";
5
+ value: string;
6
+ }
7
+ export const Button: FC<props> = ({type = "button", value}) => {
8
+
9
+ return (
10
+ <button type={type}>
11
+ {value}
12
+ </button>
13
+ );
14
+ };
15
+
16
+
@@ -0,0 +1 @@
1
+ export { Button } from './Button';
@@ -0,0 +1,59 @@
1
+ import {FC} from "react";
2
+
3
+ export interface props {
4
+ type?: "password" | "text";
5
+ wrapperClass?: string;
6
+ labelClass?: string;
7
+ inputClass?: string;
8
+ errorClass?: string;
9
+ placeholder: string;
10
+ label: string;
11
+ hasError?: string | null;
12
+ register?: any;
13
+ name?: string;
14
+ isDisabled?: boolean;
15
+ autocomplete?: boolean;
16
+ }
17
+
18
+ export const Input: FC<props> = ({
19
+ type = "text",
20
+ placeholder,
21
+ wrapperClass = "",
22
+ labelClass = "",
23
+ inputClass = "",
24
+ errorClass = "",
25
+ label,
26
+ hasError,
27
+ register, name,
28
+ isDisabled = false,
29
+ autocomplete = false,
30
+ ...otherProps
31
+ }) => {
32
+
33
+ return (
34
+ <div className={wrapperClass}>
35
+ <label
36
+ htmlFor={name}
37
+ className={`${labelClass} ${hasError && "error"}`}>
38
+ {label}
39
+ <input
40
+ disabled={isDisabled}
41
+ autoComplete={autocomplete ? "on" : "off"}
42
+ id={name}
43
+ {...register}
44
+ {...otherProps}
45
+ type={type}
46
+ name={name}
47
+ className={`${inputClass} ${hasError && "error"} ${errorClass}`}
48
+ placeholder={placeholder}
49
+ />
50
+ </label>
51
+ {
52
+ hasError &&
53
+ <p className={errorClass}>{hasError}</p>
54
+ }
55
+ </div>
56
+ );
57
+ };
58
+
59
+
@@ -0,0 +1 @@
1
+ export { Input } from './Input';
@@ -0,0 +1,171 @@
1
+ import {FC, useEffect, useState} from "react";
2
+ import AngleDown from "../../../src/assets/icons/angle-down.svg?react";
3
+ import Close from '../../../src/assets/icons/close.svg?react';
4
+ import {useWidth} from "../../../hooks/use-width";
5
+ import Loading from "../../../shared/loading/Loading";
6
+ import './select.scss';
7
+ import {addNavigation, onHashChanges, removeNavigation} from "../../utils/navigator";
8
+
9
+ export interface props {
10
+ list?: any[];
11
+ label?: string;
12
+ title: string;
13
+ value?: string;
14
+ api?: any;
15
+ maxHeight?: string;
16
+ theme?: "secondary";
17
+ hasError?: string | null;
18
+ size?: "md" | "sm";
19
+ onSelectChange?: any;
20
+ selected?: any;
21
+ }
22
+
23
+ export const Select: FC<props> = ({
24
+ list, label, hasError,
25
+ title, value, api,
26
+ maxHeight = "max-h-64", theme = "secondary", size = "md",
27
+ onSelectChange,
28
+ selected
29
+ }) => {
30
+ const getDeviceWidth = useWidth();
31
+ const [isShow, setIsShow] = useState(false);
32
+ const [isLoading, setIsLoading] = useState(true);
33
+ const [localSelected, setLocalSelected] = useState(null);
34
+ const [localList, setLocalList] = useState(null);
35
+ useEffect(() => {
36
+ if (api) {
37
+ setIsLoading(true);
38
+ api().then((res) => {
39
+ setIsLoading(false);
40
+ setLocalList(res?.data?.message ? [] : res.data);
41
+ })
42
+ }
43
+ }, [api]);
44
+ useEffect(() => {
45
+ if (getDeviceWidth < 1024) {
46
+
47
+ if (isShow) {
48
+ addNavigation('select');
49
+ document.body.style.overflow = 'hidden';
50
+ } else {
51
+
52
+ if (window.location.hash && !document.referrer.includes('#')) {
53
+ removeNavigation();
54
+ }
55
+ document.body.style.overflow = 'auto';
56
+ }
57
+ }
58
+ }, [isShow]);
59
+
60
+ useEffect(() => {
61
+ if (label?.length) {
62
+ setLocalSelected(localList?.find(item => item[label] === selected));
63
+ } else {
64
+ setLocalSelected(selected);
65
+ }
66
+ }, [selected, localList]);
67
+
68
+ useEffect(() => {
69
+ if (list?.length) {
70
+ setLocalList(list)
71
+ }
72
+ }, [list]);
73
+
74
+ const onToggle = () => {
75
+ setIsShow(prevState => !prevState);
76
+ }
77
+ const onToggleEvent = (e) => {
78
+ if (e?.target?.className.toString()?.includes('backdrop-select')) {
79
+ onToggle()
80
+ }
81
+ }
82
+ const onSelect = (item) => {
83
+ setLocalSelected(item);
84
+ onToggle();
85
+ onSelectChange(item);
86
+ }
87
+
88
+ const getActiveClass = (item) => {
89
+ if (!localSelected) {
90
+ return "";
91
+ }
92
+ if (label?.length && item[label] === localSelected[label]) {
93
+ return "bg-grey-100"
94
+ }
95
+ if (item === localSelected) {
96
+ return "bg-grey-100"
97
+ }
98
+ }
99
+ return (
100
+ <div className="naria-select">
101
+ <label
102
+ className={`cursor-pointer
103
+ ${hasError && "!text-danger-100"}`}>
104
+ <span className={``}>{title}</span>
105
+ <button type="button"
106
+ className={`relative z-20 flex items-center mt-1 text-base justify-between gap-2 w-full
107
+ ${localSelected ? "text-dark-100" : "text-grey-300"}
108
+ ${hasError && "!border-danger-100 focus:border-danger-100 outline-danger-100"}`}
109
+ onClick={onToggle}>
110
+ {
111
+ localSelected ? (
112
+ value?.length ? localSelected[value] : localSelected
113
+ ) : "انتخاب"
114
+ } <AngleDown
115
+ className={`w-4 h-4 transition ease duration-200 ${!isShow ? "rotate-0" : "rotate-180"}`}/>
116
+ </button>
117
+ </label>
118
+
119
+ {
120
+ isShow ? (
121
+ <div
122
+ className={`wrapper ${getDeviceWidth < 1024 ? "mobile" : ""}`}>
123
+ <div
124
+ className={`list ${getDeviceWidth < 1024 ? "mobile" : `desktop ${maxHeight}`}`}>
125
+ {
126
+ api && isLoading ? (
127
+ <div className="py-10 flex justify-center">
128
+ <Loading size="w-7 h-7"/>
129
+ </div>
130
+ ) : (
131
+ <>
132
+ {
133
+ getDeviceWidth < 1024 ? (
134
+ <div className="sticky top-0 text-left">
135
+ <button className="p-3" onClick={onToggle}>
136
+ <Close className="w-6"/>
137
+ </button>
138
+ </div>
139
+ ) : undefined
140
+ }
141
+ {
142
+ localList?.map((item, index) => {
143
+ return (
144
+ <button type="button" onClick={() => onSelect(item)}
145
+ key={index.toString()}
146
+ className={`text-right py-2.5 px-4 text-base hover:bg-grey-100 rounded-lg ${getActiveClass(item)}`}>
147
+ {value?.length ? item[value] : item}
148
+ </button>
149
+ )
150
+ })
151
+ }
152
+ </>
153
+ )
154
+ }
155
+ </div>
156
+ <div
157
+ className={`backdrop-select`}
158
+ onClick={onToggleEvent}>
159
+
160
+ </div>
161
+ </div>
162
+ ) : undefined
163
+ }
164
+ {
165
+ hasError &&
166
+ <p className="text-xs mt-1 text-danger-100">{hasError}</p>
167
+ }
168
+
169
+ </div>
170
+ );
171
+ };
@@ -0,0 +1 @@
1
+ export { Select } from './Select';
@@ -0,0 +1,52 @@
1
+ .naria-select {
2
+ position: relative;
3
+ .wrapper {
4
+ overflow: hidden;
5
+ &.mobile {
6
+ position: fixed;
7
+ top: 0;
8
+ right: 0;
9
+ height: 100%;
10
+ width: 100%;
11
+ z-index: 97;
12
+ }
13
+ }
14
+ .list {
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: 100%;
18
+ z-index: 99;
19
+ &.mobile {
20
+ position: relative;
21
+ height: 100%;
22
+ }
23
+ &.desktop {
24
+ overflow: auto;
25
+ position: absolute;
26
+ animation: fadeInTranslateY 0.3s ease-out forwards;
27
+ }
28
+ }
29
+ .backdrop-select {
30
+ position: fixed;
31
+ top: 0;
32
+ left: 0;
33
+ bottom: 0;
34
+ width: 100%;
35
+ height: 100%;
36
+ z-index: 98;
37
+ background-color: rgba(0, 0, 0, 0.2);
38
+ }
39
+ }
40
+
41
+
42
+
43
+ @keyframes fadeInTranslateY {
44
+ from {
45
+ opacity: 0;
46
+ transform: translateY(10px);
47
+ }
48
+ to {
49
+ opacity: 1;
50
+ transform: translateY(0);
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ export * from './Button'
2
+ export * from './Input'
3
+ export * from './Select'
package/lib/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './components';
2
+ export * from './utils';
@@ -0,0 +1,4 @@
1
+ export function capitalize(str: string): string {
2
+ return str.charAt(0).toUpperCase() + str.slice(1);
3
+ }
4
+
@@ -0,0 +1,2 @@
1
+ export * from './capitalize';
2
+
@@ -0,0 +1,29 @@
1
+ import {useEffect, useState} from "react";
2
+
3
+ export const removeNavigation = () => {
4
+ const newUrl = `${window.location.pathname}${window.location.search}`;
5
+ window.history.replaceState(null, '', newUrl);
6
+ }
7
+
8
+ export const addNavigation = (state: string) => {
9
+ window.location.hash = state;
10
+ }
11
+
12
+
13
+ export const onHashChanges = () => {
14
+ const [isHashChanged, setIsHashChanged] = useState(false)
15
+ useEffect(() => {
16
+ const handleHashChange = (e) => {
17
+ if(window.location.hash !== "#modal") {
18
+ setIsHashChanged(true);
19
+ } else {
20
+ setIsHashChanged(false);
21
+ }
22
+ };
23
+ window.addEventListener('hashchange', handleHashChange);
24
+ return () => {
25
+ window.removeEventListener('hashchange', handleHashChange);
26
+ };
27
+ }, [])
28
+ return isHashChanged
29
+ };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Mohammad Mehdi Mohammadi",
6
6
  "url": ""
7
7
  },
8
- "version": "0.1.36",
8
+ "version": "0.1.37",
9
9
  "type": "module",
10
10
  "main": "dist/naria-ui.cjs.js",
11
11
  "module": "dist/naria-ui.es.js",
@@ -15,11 +15,11 @@
15
15
  "types": "./dist/index.d.ts",
16
16
  "import": "./dist/naria-ui.es.js",
17
17
  "require": "./dist/naria-ui.cjs.js"
18
- }
18
+ },
19
+ "./dist/*.css": "./dist/*.css",
20
+ "./assets/*.css": "./assets/*.css"
19
21
  },
20
- "files": [
21
- "dist"
22
- ],
22
+ "files": ["*.md", "dist", "lib", "es", "src"],
23
23
  "publishConfig": {
24
24
  "access": "public"
25
25
  },
package/src/App.css ADDED
File without changes
package/src/App.tsx ADDED
@@ -0,0 +1,15 @@
1
+ import './App.css'
2
+ import {Button, Input, Select} from "../lib";
3
+
4
+ function App() {
5
+
6
+ return (
7
+ <>
8
+ <Button value="sadasd"/>
9
+ <Input placeholder="test" label="test"/>
10
+ <Select label="id" value="name" list = {[{id: 1, name: "sad"}]} />
11
+ </>
12
+ )
13
+ }
14
+
15
+ export default App
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M241 337c-9.4 9.4-24.6 9.4-33.9 0L47 177c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l143 143L367 143c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9L241 337z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc. --><path d="M47 239c-9.4 9.4-9.4 24.6 0 33.9L207 433c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9L97.9 256 241 113c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0L47 239z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc. --><path d="M273 239c9.4 9.4 9.4 24.6 0 33.9L113 433c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l143-143L79 113c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0L273 239z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M207 143c9.4-9.4 24.6-9.4 33.9 0L401 303c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-143-143L81 337c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9L207 143z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M480-424 284-228q-11 11-28 11t-28-11q-11-11-11-28t11-28l196-196-196-196q-11-11-11-28t11-28q11-11 28-11t28 11l196 196 196-196q11-11 28-11t28 11q11 11 11 28t-11 28L536-480l196 196q11 11 11 28t-11 28q-11 11-28 11t-28-11L480-424Z"/></svg>
@@ -0,0 +1 @@
1
+ @import "./select.scss";
@@ -0,0 +1,52 @@
1
+ .naria-select {
2
+ position: relative;
3
+ .wrapper {
4
+ overflow: hidden;
5
+ &.mobile {
6
+ position: fixed;
7
+ top: 0;
8
+ right: 0;
9
+ height: 100%;
10
+ width: 100%;
11
+ z-index: 97;
12
+ }
13
+ }
14
+ .list {
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: 100%;
18
+ z-index: 99;
19
+ &.mobile {
20
+ position: relative;
21
+ height: 100%;
22
+ }
23
+ &.desktop {
24
+ overflow: auto;
25
+ position: absolute;
26
+ animation: fadeInTranslateY 0.3s ease-out forwards;
27
+ }
28
+ }
29
+ .backdrop-select {
30
+ position: fixed;
31
+ top: 0;
32
+ left: 0;
33
+ bottom: 0;
34
+ width: 100%;
35
+ height: 100%;
36
+ z-index: 98;
37
+ background-color: rgba(0, 0, 0, 0.2);
38
+ }
39
+ }
40
+
41
+
42
+
43
+ @keyframes fadeInTranslateY {
44
+ from {
45
+ opacity: 0;
46
+ transform: translateY(10px);
47
+ }
48
+ to {
49
+ opacity: 1;
50
+ transform: translateY(0);
51
+ }
52
+ }
package/src/index.css ADDED
File without changes
package/src/main.tsx ADDED
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />