ehscan-react-components 0.1.5 → 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 CHANGED
@@ -1,79 +1,4 @@
1
- # mgsmu-react - Minimal Global State Management Utility
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
@@ -9,5 +9,5 @@ type Props = {
9
9
  click?: (args?: any) => void;
10
10
  children?: ReactNode;
11
11
  };
12
- declare const ExtButton: React.FC<Props>;
13
- export default ExtButton;
12
+ export declare const Button: React.FC<Props>;
13
+ export {};
@@ -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 ExtButton = ({ 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 ExtButton = ({ index, text, selected, addClass, notimeout, size = 'md', cl
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 ExtButton;
@@ -1,2 +1,2 @@
1
1
  import './style/button.css';
2
- export declare const myComp: () => import("react/jsx-runtime").JSX.Element;
2
+ export { Button } from './Button';
@@ -1,6 +1,5 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import ExtButton from './ExtButton';
3
1
  import './style/button.css';
4
- export const myComp = () => {
5
- return _jsx(ExtButton, {});
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.5",
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": [