ehscan-react-components 0.1.6 → 0.1.7
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/README.md +1 -76
- package/dist/Button.d.ts +2 -2
- package/dist/Button.js +1 -2
- package/dist/Components.d.ts +1 -1
- package/dist/Components.js +4 -5
- package/dist/style/button.css +250 -0
- package/dist/style/style/button.css +250 -0
- package/package.json +3 -2
- package/dist/ExtButton.d.ts +0 -13
- package/dist/ExtButton.js +0 -19
package/README.md
CHANGED
|
@@ -1,79 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
- mgsmu-react is a lightweight global state management utility for React.
|
|
4
|
-
- It provides a simple **publish-subscribe (pub-sub)** mechanism to manage global state without external libraries like Redux or Zustand.
|
|
5
|
-
- Components can subscribe to specific keys and automatically re-render when those keys change.
|
|
6
|
-
|
|
7
|
-
## install
|
|
8
|
-
```
|
|
9
|
-
npm install --save mgsmu-react
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## Import in any component
|
|
13
|
-
|
|
14
|
-
```jsx
|
|
15
|
-
import { useStateStore } from 'mgsmu-react';
|
|
16
|
-
```
|
|
17
|
-
- useStateStore() – React hook to access the global state and subscribe to changes.
|
|
18
|
-
|
|
19
|
-
## Invoke state
|
|
20
|
-
```jsx
|
|
21
|
-
const key = "data";
|
|
22
|
-
const [data, setData, removeData] = useStateStore(key);
|
|
23
|
-
```
|
|
24
|
-
- Parameter names are flexible (data, setData and removeData are just examples).
|
|
25
|
-
- keys can be used as you like. You can create as many keys as you like for different scenarios
|
|
26
|
-
|
|
27
|
-
## Set data and key
|
|
28
|
-
|
|
29
|
-
```jsx
|
|
30
|
-
const data = { specifics: "data", state: true, what: "next" };
|
|
31
|
-
setData(data)
|
|
32
|
-
|
|
33
|
-
// Functional Update 1.0.5
|
|
34
|
-
setData(prev => ({ ...prev, added: "new" }));
|
|
35
|
-
```
|
|
36
|
-
- Key: any string can be used ("data", "users", "messages", etc.)
|
|
37
|
-
- Data: any object or array can be stored under that key.
|
|
38
|
-
- Allows management of multiple independent keys in your global state
|
|
39
|
-
|
|
40
|
-
## Listen and catch changes
|
|
41
|
-
|
|
42
|
-
```jsx
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
if (!data) return;
|
|
45
|
-
console.log(data); //use Data
|
|
46
|
-
},[data])
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```jsx
|
|
50
|
-
logs: {
|
|
51
|
-
"specifics": "data",
|
|
52
|
-
"state": true,
|
|
53
|
-
"what": "next",
|
|
54
|
-
"updatedAt": 1757423800721
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
- useEffect triggers whenever the specified key (data in this example) changes.
|
|
58
|
-
- Supports multiple keys — you can set up multiple useEffect hooks to listen to different keys individually.
|
|
59
|
-
- Ensures components only re-render when the relevant slice of state updates.
|
|
60
|
-
|
|
61
|
-
## Remove keys
|
|
62
|
-
|
|
63
|
-
```jsx
|
|
64
|
-
removeData("data");
|
|
65
|
-
```
|
|
66
|
-
- Deletes a key from the global state.
|
|
67
|
-
- Make sure component is clean if rendered again
|
|
68
|
-
- Note: Triggers re-render for components subscribed to that key.
|
|
69
|
-
|
|
70
|
-
----
|
|
71
|
-
**Notes**
|
|
72
|
-
|
|
73
|
-
- Every state update includes an updatedAt timestamp.
|
|
74
|
-
- The store works with any object structure, making it flexible for various use cases.
|
|
75
|
-
- Lightweight and minimal — no context providers or extra boilerplate required.
|
|
76
|
-
- Ideal for managing small to medium app state where a full state library would be overkill.
|
|
1
|
+
# ehscan-react-components
|
|
77
2
|
|
|
78
3
|
----
|
|
79
4
|
# Changelog
|
package/dist/Button.d.ts
CHANGED
package/dist/Button.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useRef, useCallback } from "react";
|
|
3
3
|
import useRipple from "./tools/useRipple";
|
|
4
|
-
const Button = ({ index, text, selected, addClass, notimeout, size = 'md', click, children }) => {
|
|
4
|
+
export const Button = ({ index, text, selected, addClass, notimeout, size = 'md', click, children }) => {
|
|
5
5
|
const buttonRef = useRef(null);
|
|
6
6
|
const handleRipple = useRipple();
|
|
7
7
|
const handleButtonClick = useCallback((event) => {
|
|
@@ -16,4 +16,3 @@ const Button = ({ index, text, selected, addClass, notimeout, size = 'md', click
|
|
|
16
16
|
}, [notimeout, click, handleRipple]);
|
|
17
17
|
return (_jsx(_Fragment, { children: _jsxs("button", { type: "button", ref: buttonRef, onClick: handleButtonClick, className: `ext-btn ext-btn--primary ext-btn--${size} _ripple ${addClass !== null && addClass !== void 0 ? addClass : ''}`, "aria-pressed": selected, children: [children, text && _jsx("div", { className: "ext-btn-label", children: text })] }, index) }));
|
|
18
18
|
};
|
|
19
|
-
export default Button;
|
package/dist/Components.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import './style/button.css';
|
|
2
|
-
export
|
|
2
|
+
export { Button } from './Button';
|
package/dist/Components.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import Button from './Button';
|
|
3
1
|
import './style/button.css';
|
|
4
|
-
export const ExtButton = () => {
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
// export const ExtButton = () => {
|
|
3
|
+
// return <Button />
|
|
4
|
+
// }
|
|
5
|
+
export { Button } from './Button';
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/* EHSCAN Base Button */
|
|
2
|
+
|
|
3
|
+
button {
|
|
4
|
+
/* Button default variables */
|
|
5
|
+
--btn-bg: #007aff;
|
|
6
|
+
--btn-color: #fff;
|
|
7
|
+
--btn-radius: 18px;
|
|
8
|
+
--btn-padding-y: 0.5rem;
|
|
9
|
+
--btn-padding-x: 1rem;
|
|
10
|
+
--btn-width: fit-content;
|
|
11
|
+
--btn-height: auto;
|
|
12
|
+
--btn-font-size: 1rem;
|
|
13
|
+
--btn-font-weight: 500;
|
|
14
|
+
--btn-transition: all 0.2s ease;
|
|
15
|
+
--btn-line-height: 1.5;
|
|
16
|
+
--ripple-box-shadow: rgb(100 100 111 / 20%) 0px 7px 29px 0px;
|
|
17
|
+
--ripple-effect-bck: rgb(0 0 0 / 15%);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ext-btn {
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
gap: 0.5rem;
|
|
25
|
+
font-family: inherit;
|
|
26
|
+
font-size: var(--btn-font-size);
|
|
27
|
+
font-weight: var(--btn-font-weight);
|
|
28
|
+
color: var(--btn-color);
|
|
29
|
+
background-color: var(--btn-bg);
|
|
30
|
+
border: none;
|
|
31
|
+
border-radius: var(--btn-radius);
|
|
32
|
+
padding: var(--btn-padding-y) var(--btn-padding-x);
|
|
33
|
+
width: var(--btn-width);
|
|
34
|
+
height: var(--btn-height);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: var(--btn-transition);
|
|
37
|
+
text-align: center;
|
|
38
|
+
text-decoration: none;
|
|
39
|
+
user-select: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
._ripple {
|
|
43
|
+
line-height: var(--btn-line-height);
|
|
44
|
+
font-weight: var(--btn-font-weight);
|
|
45
|
+
box-shadow: var(--ripple-box-shadow);
|
|
46
|
+
position: relative;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
-webkit-user-select: none;
|
|
49
|
+
user-select: none;
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* 🧭 Focus */
|
|
56
|
+
.ext-btn:focus-visible {
|
|
57
|
+
outline: 2px solid #007aff;
|
|
58
|
+
outline-offset: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 🚫 Disabled */
|
|
62
|
+
.ext-btn:disabled,
|
|
63
|
+
.ext-btn[aria-disabled="true"] {
|
|
64
|
+
opacity: 0.6;
|
|
65
|
+
cursor: not-allowed;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Hover — slightly darker */
|
|
69
|
+
.ext-btn:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
70
|
+
filter: brightness(0.9); /* 10% darker */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* 🖱️ Hover + Active */
|
|
74
|
+
/* .ext-btn:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
75
|
+
filter: brightness(1.1);
|
|
76
|
+
} */
|
|
77
|
+
|
|
78
|
+
.ext-btn:active:not(:disabled):not([aria-disabled="true"]) {
|
|
79
|
+
transform: scale(0.97);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* 🧩 Sizes */
|
|
83
|
+
.ext-btn--sm {
|
|
84
|
+
--btn-padding-y: 0.25rem;
|
|
85
|
+
--btn-padding-x: 0.75rem;
|
|
86
|
+
--btn-font-size: 0.85rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ext-btn--md {
|
|
90
|
+
--btn-padding-y: 0.5rem;
|
|
91
|
+
--btn-padding-x: 1rem;
|
|
92
|
+
--btn-font-size: 1rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ext-btn--lg {
|
|
96
|
+
--btn-padding-y: 0.75rem;
|
|
97
|
+
--btn-padding-x: 1.5rem;
|
|
98
|
+
--btn-font-size: 1.1rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* 🎨 Variants */
|
|
102
|
+
.ext-btn--primary {
|
|
103
|
+
--btn-bg: #007aff;
|
|
104
|
+
--btn-color: #fff;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ext-btn--secondary {
|
|
108
|
+
--btn-bg: #e5e5ea;
|
|
109
|
+
--btn-color: #111;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ext-btn--outline {
|
|
113
|
+
--btn-bg: transparent;
|
|
114
|
+
--btn-color: #007aff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ext-btn--ghost {
|
|
118
|
+
--btn-bg: transparent;
|
|
119
|
+
--btn-color: #007aff;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ext-btn--danger {
|
|
123
|
+
--btn-bg: #ff3b30;
|
|
124
|
+
--btn-color: #fff;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* 🌀 Loading (optional if using spinner) */
|
|
128
|
+
.ext-btn--loading {
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
opacity: 0.8;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* 📦 Content Layout */
|
|
134
|
+
.ext-btn-icon {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
font-size: 1.1em;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ext-btn-label {
|
|
142
|
+
display: inline-block;
|
|
143
|
+
white-space: nowrap;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* RIPPLE EFFECT */
|
|
147
|
+
.ripple {
|
|
148
|
+
background: var(--ripple-effect-bck);
|
|
149
|
+
position: absolute;
|
|
150
|
+
border-radius: 50%;
|
|
151
|
+
transform: scale(0);
|
|
152
|
+
animation: ripple-animation 0.6s linear;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
transform-origin: center center;
|
|
155
|
+
will-change: transform, opacity;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Only devices that can hover (desktop/laptop) */
|
|
159
|
+
@media (hover: hover) and (pointer: fine) {
|
|
160
|
+
._ripple {
|
|
161
|
+
cursor: pointer;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@keyframes ripple-animation {
|
|
167
|
+
to {
|
|
168
|
+
transform: scale(4);
|
|
169
|
+
opacity: 0;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.lds-ripple,
|
|
174
|
+
.lds-ripple div {
|
|
175
|
+
box-sizing: border-box;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.lds-ripple {
|
|
179
|
+
--image-sync-wh: 100%;
|
|
180
|
+
--bw: 5px;
|
|
181
|
+
position: absolute;
|
|
182
|
+
top: 50%;
|
|
183
|
+
left: 50%;
|
|
184
|
+
transform: translate(-50%, -50%);
|
|
185
|
+
height: var(--image-sync-wh);
|
|
186
|
+
width: var(--image-sync-wh);
|
|
187
|
+
z-index: 9999;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.lds-ripple div {
|
|
191
|
+
position: absolute;
|
|
192
|
+
border: var(--bw) solid white;
|
|
193
|
+
opacity: 1;
|
|
194
|
+
border-radius: 50%;
|
|
195
|
+
animation: lds-ripple 1s cubic-bezier(0, 0.4, 0.8, 1) infinite;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.lds-ripple div:nth-child(2) {
|
|
199
|
+
animation-delay: -0.5s;
|
|
200
|
+
border: var(--bw) solid whitesmoke;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@keyframes lds-ripple {
|
|
204
|
+
0% {
|
|
205
|
+
top: 50%;
|
|
206
|
+
left: 50%;
|
|
207
|
+
width: 8%;
|
|
208
|
+
height: 8%;
|
|
209
|
+
opacity: .2;
|
|
210
|
+
transform: translate(-50%, -50%);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
5% {
|
|
214
|
+
top: 50%;
|
|
215
|
+
left: 50%;
|
|
216
|
+
width: 8%;
|
|
217
|
+
height: 8%;
|
|
218
|
+
opacity: 1;
|
|
219
|
+
transform: translate(-50%, -50%);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
100% {
|
|
223
|
+
top: 50%;
|
|
224
|
+
left: 50%;
|
|
225
|
+
width: var(--image-sync-wh);
|
|
226
|
+
height: var(--image-sync-wh);
|
|
227
|
+
opacity: .2;
|
|
228
|
+
transform: translate(-50%, -50%);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.closeBtn{
|
|
233
|
+
--btn-width: 35px;
|
|
234
|
+
--btn-height: 35px;
|
|
235
|
+
padding: 0;
|
|
236
|
+
--btn-bg: lightgray;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.saveBtn{
|
|
240
|
+
--btn-height: 35px;
|
|
241
|
+
--btn-padding-x: 30px;
|
|
242
|
+
--btn-bg: #007aff;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.trashBtn{
|
|
246
|
+
--btn-height: 35px;
|
|
247
|
+
--btn-padding-x: 10px;
|
|
248
|
+
--btn-radius: 4px;
|
|
249
|
+
--btn-bg: lightgray;
|
|
250
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/* EHSCAN Base Button */
|
|
2
|
+
|
|
3
|
+
button {
|
|
4
|
+
/* Button default variables */
|
|
5
|
+
--btn-bg: #007aff;
|
|
6
|
+
--btn-color: #fff;
|
|
7
|
+
--btn-radius: 18px;
|
|
8
|
+
--btn-padding-y: 0.5rem;
|
|
9
|
+
--btn-padding-x: 1rem;
|
|
10
|
+
--btn-width: fit-content;
|
|
11
|
+
--btn-height: auto;
|
|
12
|
+
--btn-font-size: 1rem;
|
|
13
|
+
--btn-font-weight: 500;
|
|
14
|
+
--btn-transition: all 0.2s ease;
|
|
15
|
+
--btn-line-height: 1.5;
|
|
16
|
+
--ripple-box-shadow: rgb(100 100 111 / 20%) 0px 7px 29px 0px;
|
|
17
|
+
--ripple-effect-bck: rgb(0 0 0 / 15%);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ext-btn {
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
gap: 0.5rem;
|
|
25
|
+
font-family: inherit;
|
|
26
|
+
font-size: var(--btn-font-size);
|
|
27
|
+
font-weight: var(--btn-font-weight);
|
|
28
|
+
color: var(--btn-color);
|
|
29
|
+
background-color: var(--btn-bg);
|
|
30
|
+
border: none;
|
|
31
|
+
border-radius: var(--btn-radius);
|
|
32
|
+
padding: var(--btn-padding-y) var(--btn-padding-x);
|
|
33
|
+
width: var(--btn-width);
|
|
34
|
+
height: var(--btn-height);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: var(--btn-transition);
|
|
37
|
+
text-align: center;
|
|
38
|
+
text-decoration: none;
|
|
39
|
+
user-select: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
._ripple {
|
|
43
|
+
line-height: var(--btn-line-height);
|
|
44
|
+
font-weight: var(--btn-font-weight);
|
|
45
|
+
box-shadow: var(--ripple-box-shadow);
|
|
46
|
+
position: relative;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
-webkit-user-select: none;
|
|
49
|
+
user-select: none;
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* 🧭 Focus */
|
|
56
|
+
.ext-btn:focus-visible {
|
|
57
|
+
outline: 2px solid #007aff;
|
|
58
|
+
outline-offset: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 🚫 Disabled */
|
|
62
|
+
.ext-btn:disabled,
|
|
63
|
+
.ext-btn[aria-disabled="true"] {
|
|
64
|
+
opacity: 0.6;
|
|
65
|
+
cursor: not-allowed;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Hover — slightly darker */
|
|
69
|
+
.ext-btn:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
70
|
+
filter: brightness(0.9); /* 10% darker */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* 🖱️ Hover + Active */
|
|
74
|
+
/* .ext-btn:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
75
|
+
filter: brightness(1.1);
|
|
76
|
+
} */
|
|
77
|
+
|
|
78
|
+
.ext-btn:active:not(:disabled):not([aria-disabled="true"]) {
|
|
79
|
+
transform: scale(0.97);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* 🧩 Sizes */
|
|
83
|
+
.ext-btn--sm {
|
|
84
|
+
--btn-padding-y: 0.25rem;
|
|
85
|
+
--btn-padding-x: 0.75rem;
|
|
86
|
+
--btn-font-size: 0.85rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ext-btn--md {
|
|
90
|
+
--btn-padding-y: 0.5rem;
|
|
91
|
+
--btn-padding-x: 1rem;
|
|
92
|
+
--btn-font-size: 1rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ext-btn--lg {
|
|
96
|
+
--btn-padding-y: 0.75rem;
|
|
97
|
+
--btn-padding-x: 1.5rem;
|
|
98
|
+
--btn-font-size: 1.1rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* 🎨 Variants */
|
|
102
|
+
.ext-btn--primary {
|
|
103
|
+
--btn-bg: #007aff;
|
|
104
|
+
--btn-color: #fff;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ext-btn--secondary {
|
|
108
|
+
--btn-bg: #e5e5ea;
|
|
109
|
+
--btn-color: #111;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ext-btn--outline {
|
|
113
|
+
--btn-bg: transparent;
|
|
114
|
+
--btn-color: #007aff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ext-btn--ghost {
|
|
118
|
+
--btn-bg: transparent;
|
|
119
|
+
--btn-color: #007aff;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ext-btn--danger {
|
|
123
|
+
--btn-bg: #ff3b30;
|
|
124
|
+
--btn-color: #fff;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* 🌀 Loading (optional if using spinner) */
|
|
128
|
+
.ext-btn--loading {
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
opacity: 0.8;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* 📦 Content Layout */
|
|
134
|
+
.ext-btn-icon {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
font-size: 1.1em;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ext-btn-label {
|
|
142
|
+
display: inline-block;
|
|
143
|
+
white-space: nowrap;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* RIPPLE EFFECT */
|
|
147
|
+
.ripple {
|
|
148
|
+
background: var(--ripple-effect-bck);
|
|
149
|
+
position: absolute;
|
|
150
|
+
border-radius: 50%;
|
|
151
|
+
transform: scale(0);
|
|
152
|
+
animation: ripple-animation 0.6s linear;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
transform-origin: center center;
|
|
155
|
+
will-change: transform, opacity;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Only devices that can hover (desktop/laptop) */
|
|
159
|
+
@media (hover: hover) and (pointer: fine) {
|
|
160
|
+
._ripple {
|
|
161
|
+
cursor: pointer;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@keyframes ripple-animation {
|
|
167
|
+
to {
|
|
168
|
+
transform: scale(4);
|
|
169
|
+
opacity: 0;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.lds-ripple,
|
|
174
|
+
.lds-ripple div {
|
|
175
|
+
box-sizing: border-box;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.lds-ripple {
|
|
179
|
+
--image-sync-wh: 100%;
|
|
180
|
+
--bw: 5px;
|
|
181
|
+
position: absolute;
|
|
182
|
+
top: 50%;
|
|
183
|
+
left: 50%;
|
|
184
|
+
transform: translate(-50%, -50%);
|
|
185
|
+
height: var(--image-sync-wh);
|
|
186
|
+
width: var(--image-sync-wh);
|
|
187
|
+
z-index: 9999;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.lds-ripple div {
|
|
191
|
+
position: absolute;
|
|
192
|
+
border: var(--bw) solid white;
|
|
193
|
+
opacity: 1;
|
|
194
|
+
border-radius: 50%;
|
|
195
|
+
animation: lds-ripple 1s cubic-bezier(0, 0.4, 0.8, 1) infinite;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.lds-ripple div:nth-child(2) {
|
|
199
|
+
animation-delay: -0.5s;
|
|
200
|
+
border: var(--bw) solid whitesmoke;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@keyframes lds-ripple {
|
|
204
|
+
0% {
|
|
205
|
+
top: 50%;
|
|
206
|
+
left: 50%;
|
|
207
|
+
width: 8%;
|
|
208
|
+
height: 8%;
|
|
209
|
+
opacity: .2;
|
|
210
|
+
transform: translate(-50%, -50%);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
5% {
|
|
214
|
+
top: 50%;
|
|
215
|
+
left: 50%;
|
|
216
|
+
width: 8%;
|
|
217
|
+
height: 8%;
|
|
218
|
+
opacity: 1;
|
|
219
|
+
transform: translate(-50%, -50%);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
100% {
|
|
223
|
+
top: 50%;
|
|
224
|
+
left: 50%;
|
|
225
|
+
width: var(--image-sync-wh);
|
|
226
|
+
height: var(--image-sync-wh);
|
|
227
|
+
opacity: .2;
|
|
228
|
+
transform: translate(-50%, -50%);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.closeBtn{
|
|
233
|
+
--btn-width: 35px;
|
|
234
|
+
--btn-height: 35px;
|
|
235
|
+
padding: 0;
|
|
236
|
+
--btn-bg: lightgray;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.saveBtn{
|
|
240
|
+
--btn-height: 35px;
|
|
241
|
+
--btn-padding-x: 30px;
|
|
242
|
+
--btn-bg: #007aff;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.trashBtn{
|
|
246
|
+
--btn-height: 35px;
|
|
247
|
+
--btn-padding-x: 10px;
|
|
248
|
+
--btn-radius: 4px;
|
|
249
|
+
--btn-bg: lightgray;
|
|
250
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ehscan-react-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "components",
|
|
5
5
|
"main": "dist/Components.js",
|
|
6
6
|
"types": "dist/Components.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
8
|
+
"build": "tsc && npm run copy-css",
|
|
9
|
+
"copy-css": "cp -r src/style dist/style",
|
|
9
10
|
"prepublishOnly": "npm run build"
|
|
10
11
|
},
|
|
11
12
|
"keywords": [
|
package/dist/ExtButton.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
type Props = {
|
|
3
|
-
index?: string | number;
|
|
4
|
-
text?: string;
|
|
5
|
-
selected?: boolean;
|
|
6
|
-
addClass?: string;
|
|
7
|
-
notimeout?: boolean;
|
|
8
|
-
size?: 'sm' | 'md' | 'lg';
|
|
9
|
-
click?: (args?: any) => void;
|
|
10
|
-
children?: ReactNode;
|
|
11
|
-
};
|
|
12
|
-
declare const ExtButton: React.FC<Props>;
|
|
13
|
-
export default ExtButton;
|
package/dist/ExtButton.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useCallback } from "react";
|
|
3
|
-
import useRipple from "./tools/useRipple";
|
|
4
|
-
const ExtButton = ({ index, text, selected, addClass, notimeout, size = 'md', click, children }) => {
|
|
5
|
-
const buttonRef = useRef(null);
|
|
6
|
-
const handleRipple = useRipple();
|
|
7
|
-
const handleButtonClick = useCallback((event) => {
|
|
8
|
-
handleRipple(event, buttonRef);
|
|
9
|
-
if (notimeout) {
|
|
10
|
-
click === null || click === void 0 ? void 0 : click(event);
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
setTimeout(() => {
|
|
14
|
-
click === null || click === void 0 ? void 0 : click(event);
|
|
15
|
-
}, 200);
|
|
16
|
-
}, [notimeout, click, handleRipple]);
|
|
17
|
-
return (_jsx(_Fragment, { children: _jsxs("button", { type: "button", ref: buttonRef, onClick: handleButtonClick, className: `ext-btn ext-btn--primary ext-btn--${size} _ripple ${addClass !== null && addClass !== void 0 ? addClass : ''}`, "aria-pressed": selected, children: [children, text && _jsx("div", { className: "ext-btn-label", children: text })] }, index) }));
|
|
18
|
-
};
|
|
19
|
-
export default ExtButton;
|