@ews-admin/global-design-system 1.1.14 → 1.1.15
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/dist/components/Logo/Logo.d.ts +3 -27
- package/dist/components/Logo/Logo.d.ts.map +1 -1
- package/dist/components/Logo/Logo.types.d.ts +41 -0
- package/dist/components/Logo/Logo.types.d.ts.map +1 -0
- package/dist/components/Logo/index.d.ts +1 -1
- package/dist/components/Logo/index.d.ts.map +1 -1
- package/dist/components/Logo/logoAssets.d.ts +1 -0
- package/dist/components/Logo/logoAssets.d.ts.map +1 -0
- package/dist/components/SearchAutocomplete/SearchAutocomplete.d.ts +1 -1
- package/dist/components/SearchAutocomplete/SearchAutocomplete.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +3 -3
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/hooks/useSelectField.d.ts +4 -4
- package/dist/hooks/useSelectField.d.ts.map +1 -1
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/icons/Icon.d.ts.map +1 -1
- package/dist/index.css +2 -2
- package/dist/index.d.ts +30 -14
- package/dist/index.esm.css +2 -2
- package/dist/index.esm.js +55 -21
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +54 -20
- package/dist/index.js.map +1 -1
- package/dist/styles/theme-variables.css +62 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Logo/Logo.tsx +65 -45
- package/src/components/Logo/Logo.types.ts +42 -0
- package/src/components/Logo/index.ts +1 -1
- package/src/components/SearchAutocomplete/SearchAutocomplete.tsx +1 -1
- package/src/components/Select/Select.tsx +21 -8
- package/src/hooks/useSelectField.ts +7 -2
- package/src/icons/Icon.tsx +1 -1
- package/src/styles/index.css +0 -32
- package/src/utils/index.ts +5 -3
- package/tailwind.preset.js +23 -23
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* EWS Design System - Theme CSS Variables */
|
|
2
|
+
/* This file should be imported in consuming applications */
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
/* PROMED Theme (Default) - Professional theme for doctors/managers */
|
|
6
|
+
--ews-primary: #21596c;
|
|
7
|
+
--ews-primary-hover: #1a4756;
|
|
8
|
+
--ews-primary-light: #c0d0d4;
|
|
9
|
+
--ews-secondary: #3ba1a1;
|
|
10
|
+
--ews-secondary-hover: #308181;
|
|
11
|
+
--ews-success: #059669;
|
|
12
|
+
--ews-success-hover: #047857;
|
|
13
|
+
--ews-warning: #d97706;
|
|
14
|
+
--ews-warning-hover: #b45309;
|
|
15
|
+
--ews-error: #dc2626;
|
|
16
|
+
--ews-error-hover: #b91c1c;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Default theme when no data-theme is set */
|
|
20
|
+
html:not([data-theme]) {
|
|
21
|
+
--ews-primary: #21596c;
|
|
22
|
+
--ews-primary-hover: #1a4756;
|
|
23
|
+
--ews-primary-light: #c0d0d4;
|
|
24
|
+
--ews-secondary: #3ba1a1;
|
|
25
|
+
--ews-secondary-hover: #308181;
|
|
26
|
+
--ews-success: #059669;
|
|
27
|
+
--ews-success-hover: #047857;
|
|
28
|
+
--ews-warning: #d97706;
|
|
29
|
+
--ews-warning-hover: #b45309;
|
|
30
|
+
--ews-error: #dc2626;
|
|
31
|
+
--ews-error-hover: #b91c1c;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* MED Theme - Patient-friendly theme */
|
|
35
|
+
[data-theme="MED"] {
|
|
36
|
+
--ews-primary: #3ba1a1;
|
|
37
|
+
--ews-primary-hover: #308181;
|
|
38
|
+
--ews-primary-light: #a8d5d5;
|
|
39
|
+
--ews-secondary: #6b73ff;
|
|
40
|
+
--ews-secondary-hover: #5a61e6;
|
|
41
|
+
--ews-success: #059669;
|
|
42
|
+
--ews-success-hover: #047857;
|
|
43
|
+
--ews-warning: #d97706;
|
|
44
|
+
--ews-warning-hover: #b45309;
|
|
45
|
+
--ews-error: #dc2626;
|
|
46
|
+
--ews-error-hover: #b91c1c;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* PROMED Theme - Professional theme */
|
|
50
|
+
[data-theme="PROMED"] {
|
|
51
|
+
--ews-primary: #21596c;
|
|
52
|
+
--ews-primary-hover: #1a4756;
|
|
53
|
+
--ews-primary-light: #c0d0d4;
|
|
54
|
+
--ews-secondary: #3ba1a1;
|
|
55
|
+
--ews-secondary-hover: #308181;
|
|
56
|
+
--ews-success: #059669;
|
|
57
|
+
--ews-success-hover: #047857;
|
|
58
|
+
--ews-warning: #d97706;
|
|
59
|
+
--ews-warning-hover: #b45309;
|
|
60
|
+
--ews-error: #dc2626;
|
|
61
|
+
--ews-error-hover: #b91c1c;
|
|
62
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function formatDate(date: Date | string | number, options?: Intl.
|
|
|
29
29
|
* @param wait - Wait time in milliseconds
|
|
30
30
|
* @returns Debounced function
|
|
31
31
|
*/
|
|
32
|
-
export declare function debounce<T extends (...args:
|
|
32
|
+
export declare function debounce<T extends (...args: unknown[]) => unknown>(func: T, wait: number): (...args: Parameters<T>) => void;
|
|
33
33
|
/**
|
|
34
34
|
* Utility function to generate unique ID
|
|
35
35
|
* @param prefix - Optional prefix for the ID
|
|
@@ -44,7 +44,7 @@ export declare function generateId(prefix?: string): string;
|
|
|
44
44
|
export declare const formatNumeric: (value: string) => string;
|
|
45
45
|
/**
|
|
46
46
|
* Utility function to validate phone numbers
|
|
47
|
-
* Validates phone numbers with 1-
|
|
47
|
+
* Validates phone numbers with 1-17 digits, optionally starting with + symbol
|
|
48
48
|
* @param value - Phone number string to validate
|
|
49
49
|
* @returns Boolean indicating if the phone number is valid
|
|
50
50
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAE9B;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAW,GAAG,MAAM,CAK1E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC5B,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,GACnC,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAE9B;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAW,GAAG,MAAM,CAK1E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC5B,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,GACnC,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAChE,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,MAAM,GACX,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAMlC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,SAAQ,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAE7C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAMzD"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../utils";
|
|
2
|
-
|
|
3
|
-
export interface LogoProps {
|
|
4
|
-
/**
|
|
5
|
-
* Logo size
|
|
6
|
-
*/
|
|
7
|
-
size?: "sm" | "md" | "lg" | "xl";
|
|
8
|
-
/**
|
|
9
|
-
* Whether to show the tagline
|
|
10
|
-
*/
|
|
11
|
-
showTagline?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Whether to show only the icon (favicon version)
|
|
14
|
-
*/
|
|
15
|
-
iconOnly?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Logo variant - normal, white, or favicon
|
|
18
|
-
*/
|
|
19
|
-
variant?: "normal" | "white" | "fullWhite" | "favicon";
|
|
20
|
-
/**
|
|
21
|
-
* Custom className
|
|
22
|
-
*/
|
|
23
|
-
className?: string;
|
|
24
|
-
/**
|
|
25
|
-
* Click handler
|
|
26
|
-
*/
|
|
27
|
-
onClick?: () => void;
|
|
28
|
-
}
|
|
2
|
+
import type { LogoProps } from "./Logo.types";
|
|
29
3
|
|
|
30
4
|
const Logo = ({
|
|
31
5
|
size = "md",
|
|
@@ -34,6 +8,9 @@ const Logo = ({
|
|
|
34
8
|
variant = "normal",
|
|
35
9
|
className,
|
|
36
10
|
onClick,
|
|
11
|
+
customSrc,
|
|
12
|
+
alt = "MEDECINE 360 Logo",
|
|
13
|
+
clickable = false,
|
|
37
14
|
}: LogoProps) => {
|
|
38
15
|
const sizes = {
|
|
39
16
|
sm: "h-8",
|
|
@@ -49,17 +26,21 @@ const Logo = ({
|
|
|
49
26
|
xl: "h-16 w-16",
|
|
50
27
|
};
|
|
51
28
|
|
|
52
|
-
// Get the appropriate logo image based on variant
|
|
53
|
-
// For iconOnly, always use favicon.ico
|
|
54
|
-
const logoSrc =
|
|
55
|
-
|
|
56
|
-
|
|
29
|
+
// Get the appropriate logo image based on variant or custom source
|
|
30
|
+
// For iconOnly, always use favicon.ico unless customSrc is provided
|
|
31
|
+
const logoSrc =
|
|
32
|
+
customSrc ||
|
|
33
|
+
(iconOnly
|
|
34
|
+
? "/favicon.ico"
|
|
35
|
+
: variant === "white"
|
|
57
36
|
? "/image/logoWhite.png"
|
|
58
37
|
: variant === "fullWhite"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
38
|
+
? "/image/logoFullWhite.png"
|
|
39
|
+
: variant === "favicon"
|
|
40
|
+
? "/favicon.ico"
|
|
41
|
+
: "/image/logo.png");
|
|
42
|
+
|
|
43
|
+
const isClickable = clickable || !!onClick;
|
|
63
44
|
|
|
64
45
|
if (iconOnly) {
|
|
65
46
|
return (
|
|
@@ -67,16 +48,33 @@ const Logo = ({
|
|
|
67
48
|
className={cn(
|
|
68
49
|
"flex items-center justify-center",
|
|
69
50
|
iconSizes[size],
|
|
51
|
+
isClickable && "cursor-pointer",
|
|
70
52
|
className
|
|
71
53
|
)}
|
|
72
54
|
onClick={onClick}
|
|
73
|
-
role={
|
|
74
|
-
tabIndex={
|
|
55
|
+
role={isClickable ? "button" : undefined}
|
|
56
|
+
tabIndex={isClickable ? 0 : undefined}
|
|
57
|
+
onKeyDown={
|
|
58
|
+
isClickable
|
|
59
|
+
? (e) => {
|
|
60
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
onClick?.();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
: undefined
|
|
66
|
+
}
|
|
75
67
|
>
|
|
76
68
|
<img
|
|
77
69
|
src={logoSrc}
|
|
78
|
-
alt=
|
|
79
|
-
className="w-full h-full
|
|
70
|
+
alt={alt}
|
|
71
|
+
className="object-contain w-full h-full"
|
|
72
|
+
onError={(e) => {
|
|
73
|
+
// Fallback to favicon if image fails to load
|
|
74
|
+
if (logoSrc !== "/favicon.ico") {
|
|
75
|
+
(e.target as unknown as { src: string }).src = "/favicon.ico";
|
|
76
|
+
}
|
|
77
|
+
}}
|
|
80
78
|
/>
|
|
81
79
|
</div>
|
|
82
80
|
);
|
|
@@ -84,19 +82,41 @@ const Logo = ({
|
|
|
84
82
|
|
|
85
83
|
return (
|
|
86
84
|
<div
|
|
87
|
-
className={cn(
|
|
85
|
+
className={cn(
|
|
86
|
+
"flex items-center",
|
|
87
|
+
sizes[size],
|
|
88
|
+
isClickable && "cursor-pointer",
|
|
89
|
+
className
|
|
90
|
+
)}
|
|
88
91
|
onClick={onClick}
|
|
89
|
-
role={
|
|
90
|
-
tabIndex={
|
|
92
|
+
role={isClickable ? "button" : undefined}
|
|
93
|
+
tabIndex={isClickable ? 0 : undefined}
|
|
94
|
+
onKeyDown={
|
|
95
|
+
isClickable
|
|
96
|
+
? (e) => {
|
|
97
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
onClick?.();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
: undefined
|
|
103
|
+
}
|
|
91
104
|
>
|
|
92
105
|
{/* Logo Image */}
|
|
93
106
|
<img
|
|
94
107
|
src={logoSrc}
|
|
95
|
-
alt=
|
|
96
|
-
className="
|
|
108
|
+
alt={alt}
|
|
109
|
+
className="object-contain w-auto h-full"
|
|
110
|
+
onError={(e) => {
|
|
111
|
+
// Fallback to favicon if image fails to load
|
|
112
|
+
if (logoSrc !== "/favicon.ico") {
|
|
113
|
+
(e.target as unknown as { src: string }).src = "/favicon.ico";
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
97
116
|
/>
|
|
98
117
|
</div>
|
|
99
118
|
);
|
|
100
119
|
};
|
|
101
120
|
|
|
121
|
+
export type { LogoProps, LogoSize, LogoVariant } from "./Logo.types";
|
|
102
122
|
export { Logo };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type LogoSize = "sm" | "md" | "lg" | "xl";
|
|
2
|
+
|
|
3
|
+
export type LogoVariant = "normal" | "white" | "fullWhite" | "favicon";
|
|
4
|
+
|
|
5
|
+
export interface LogoProps {
|
|
6
|
+
/**
|
|
7
|
+
* Logo size
|
|
8
|
+
*/
|
|
9
|
+
size?: LogoSize;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to show the tagline
|
|
12
|
+
*/
|
|
13
|
+
showTagline?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether to show only the icon (favicon version)
|
|
16
|
+
*/
|
|
17
|
+
iconOnly?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Logo variant - normal, white, or favicon
|
|
20
|
+
*/
|
|
21
|
+
variant?: LogoVariant;
|
|
22
|
+
/**
|
|
23
|
+
* Custom className
|
|
24
|
+
*/
|
|
25
|
+
className?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Click handler
|
|
28
|
+
*/
|
|
29
|
+
onClick?: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Custom logo source URL (overrides variant)
|
|
32
|
+
*/
|
|
33
|
+
customSrc?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Alt text for the logo image
|
|
36
|
+
*/
|
|
37
|
+
alt?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the logo is clickable (adds cursor pointer)
|
|
40
|
+
*/
|
|
41
|
+
clickable?: boolean;
|
|
42
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Logo } from "./Logo";
|
|
2
|
-
export type { LogoProps } from "./Logo";
|
|
2
|
+
export type { LogoProps, LogoSize, LogoVariant } from "./Logo";
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { ChevronDown, Search, X } from "lucide-react";
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
3
10
|
import { cn } from "../../utils";
|
|
4
11
|
import { Input } from "../Input";
|
|
5
12
|
|
|
6
|
-
export interface SelectOption<T =
|
|
13
|
+
export interface SelectOption<T = unknown> {
|
|
7
14
|
value: T;
|
|
8
15
|
label: string;
|
|
9
16
|
disabled?: boolean;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
export interface SelectProps<T =
|
|
19
|
+
export interface SelectProps<T = unknown> {
|
|
13
20
|
/**
|
|
14
21
|
* Array of options to display
|
|
15
22
|
*/
|
|
@@ -149,7 +156,7 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(
|
|
|
149
156
|
: options;
|
|
150
157
|
|
|
151
158
|
// Calculate dropdown position based on available space
|
|
152
|
-
const calculateDropdownPosition = () => {
|
|
159
|
+
const calculateDropdownPosition = useCallback(() => {
|
|
153
160
|
if (!containerRef.current) return;
|
|
154
161
|
|
|
155
162
|
const containerRect = containerRef.current.getBoundingClientRect();
|
|
@@ -190,7 +197,7 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(
|
|
|
190
197
|
} else {
|
|
191
198
|
setDropdownPosition("bottom");
|
|
192
199
|
}
|
|
193
|
-
};
|
|
200
|
+
}, [filteredOptions.length, searchable, maxHeight]);
|
|
194
201
|
|
|
195
202
|
// Alternative calculation using actual dropdown element when available
|
|
196
203
|
const calculateDropdownPositionWithElement = () => {
|
|
@@ -252,7 +259,13 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(
|
|
|
252
259
|
calculateDropdownPositionWithElement();
|
|
253
260
|
});
|
|
254
261
|
}
|
|
255
|
-
}, [
|
|
262
|
+
}, [
|
|
263
|
+
isOpen,
|
|
264
|
+
filteredOptions.length,
|
|
265
|
+
searchable,
|
|
266
|
+
maxHeight,
|
|
267
|
+
calculateDropdownPosition,
|
|
268
|
+
]);
|
|
256
269
|
|
|
257
270
|
// Recalculate position on window resize
|
|
258
271
|
useEffect(() => {
|
|
@@ -269,7 +282,7 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(
|
|
|
269
282
|
window.removeEventListener("resize", handleResize);
|
|
270
283
|
window.removeEventListener("scroll", handleResize);
|
|
271
284
|
};
|
|
272
|
-
}, [isOpen]);
|
|
285
|
+
}, [isOpen, calculateDropdownPosition]);
|
|
273
286
|
|
|
274
287
|
// Handle keyboard navigation
|
|
275
288
|
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
@@ -335,7 +348,7 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(
|
|
|
335
348
|
// Handle clear
|
|
336
349
|
const handleClear = (event: React.MouseEvent) => {
|
|
337
350
|
event.stopPropagation();
|
|
338
|
-
onChange?.(undefined as
|
|
351
|
+
onChange?.(undefined as unknown, {} as SelectOption);
|
|
339
352
|
};
|
|
340
353
|
|
|
341
354
|
// Handle toggle
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Control,
|
|
3
3
|
FieldPath,
|
|
4
|
+
FieldPathValue,
|
|
4
5
|
FieldValues,
|
|
6
|
+
RegisterOptions,
|
|
5
7
|
useController,
|
|
6
8
|
} from "react-hook-form";
|
|
7
9
|
import { SelectOption, SelectProps } from "../components/Select";
|
|
@@ -13,8 +15,11 @@ export interface UseSelectFieldProps<
|
|
|
13
15
|
name: TName;
|
|
14
16
|
control: Control<TFieldValues>;
|
|
15
17
|
options: SelectOption[];
|
|
16
|
-
rules?:
|
|
17
|
-
|
|
18
|
+
rules?: Omit<
|
|
19
|
+
RegisterOptions<TFieldValues, TName>,
|
|
20
|
+
"disabled" | "valueAsNumber" | "valueAsDate" | "setValueAs"
|
|
21
|
+
>;
|
|
22
|
+
defaultValue?: FieldPathValue<TFieldValues, TName>;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export function useSelectField<
|
package/src/icons/Icon.tsx
CHANGED
package/src/styles/index.css
CHANGED
|
@@ -287,36 +287,4 @@ div[tabindex]:focus {
|
|
|
287
287
|
.hover-scale:hover {
|
|
288
288
|
transform: scale(1.02);
|
|
289
289
|
}
|
|
290
|
-
|
|
291
|
-
/* Custom checkbox styling for better control */
|
|
292
|
-
input[type="checkbox"] {
|
|
293
|
-
width: 1rem;
|
|
294
|
-
height: 1rem;
|
|
295
|
-
border-radius: 0.25rem;
|
|
296
|
-
border: 2px solid var(--ews-gray-300);
|
|
297
|
-
background-color: white;
|
|
298
|
-
cursor: pointer;
|
|
299
|
-
transition: all 0.2s ease-in-out;
|
|
300
|
-
accent-color: var(--ews-primary);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
input[type="checkbox"]:hover {
|
|
304
|
-
border-color: var(--ews-primary);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
input[type="checkbox"]:focus {
|
|
308
|
-
outline: none;
|
|
309
|
-
border-color: var(--ews-primary);
|
|
310
|
-
box-shadow: 0 0 0 2px var(--ews-primary);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
input[type="checkbox"]:checked {
|
|
314
|
-
background-color: var(--ews-primary);
|
|
315
|
-
border-color: var(--ews-primary);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
input[type="checkbox"]:disabled {
|
|
319
|
-
opacity: 0.5;
|
|
320
|
-
cursor: not-allowed;
|
|
321
|
-
}
|
|
322
290
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ export function formatDate(
|
|
|
52
52
|
* @param wait - Wait time in milliseconds
|
|
53
53
|
* @returns Debounced function
|
|
54
54
|
*/
|
|
55
|
-
export function debounce<T extends (...args:
|
|
55
|
+
export function debounce<T extends (...args: unknown[]) => unknown>(
|
|
56
56
|
func: T,
|
|
57
57
|
wait: number
|
|
58
58
|
): (...args: Parameters<T>) => void {
|
|
@@ -83,12 +83,14 @@ export const formatNumeric = (value: string): string => {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Utility function to validate phone numbers
|
|
86
|
-
* Validates phone numbers with 1-
|
|
86
|
+
* Validates phone numbers with 1-17 digits, optionally starting with + symbol
|
|
87
87
|
* @param value - Phone number string to validate
|
|
88
88
|
* @returns Boolean indicating if the phone number is valid
|
|
89
89
|
*/
|
|
90
90
|
export function isValidPhoneNumber(value: string): boolean {
|
|
91
91
|
const trimmedValue = value.trim();
|
|
92
|
-
|
|
92
|
+
// Allow + at the beginning, followed by 1-17 digits
|
|
93
|
+
// Or just 1-17 digits without +
|
|
94
|
+
const phoneRegex = /^(\+\d{1,17}|\d{1,17})$/;
|
|
93
95
|
return phoneRegex.test(trimmedValue);
|
|
94
96
|
}
|
package/tailwind.preset.js
CHANGED
|
@@ -4,18 +4,18 @@ module.exports = {
|
|
|
4
4
|
theme: {
|
|
5
5
|
extend: {
|
|
6
6
|
colors: {
|
|
7
|
-
// EWS Theme Colors - These
|
|
8
|
-
"ews-primary": "
|
|
9
|
-
"ews-primary-hover": "
|
|
10
|
-
"ews-primary-light": "
|
|
11
|
-
"ews-secondary": "
|
|
12
|
-
"ews-secondary-hover": "
|
|
13
|
-
"ews-success": "
|
|
14
|
-
"ews-success-hover": "
|
|
15
|
-
"ews-warning": "
|
|
16
|
-
"ews-warning-hover": "
|
|
17
|
-
"ews-error": "
|
|
18
|
-
"ews-error-hover": "
|
|
7
|
+
// EWS Theme Colors - These will be available as CSS variables
|
|
8
|
+
"ews-primary": "var(--ews-primary, #21596c)",
|
|
9
|
+
"ews-primary-hover": "var(--ews-primary-hover, #1a4756)",
|
|
10
|
+
"ews-primary-light": "var(--ews-primary-light, #c0d0d4)",
|
|
11
|
+
"ews-secondary": "var(--ews-secondary, #3ba1a1)",
|
|
12
|
+
"ews-secondary-hover": "var(--ews-secondary-hover, #308181)",
|
|
13
|
+
"ews-success": "var(--ews-success, #059669)",
|
|
14
|
+
"ews-success-hover": "var(--ews-success-hover, #047857)",
|
|
15
|
+
"ews-warning": "var(--ews-warning, #d97706)",
|
|
16
|
+
"ews-warning-hover": "var(--ews-warning-hover, #b45309)",
|
|
17
|
+
"ews-error": "var(--ews-error, #dc2626)",
|
|
18
|
+
"ews-error-hover": "var(--ews-error-hover, #b91c1c)",
|
|
19
19
|
|
|
20
20
|
// EWS Gray Scale
|
|
21
21
|
"ews-gray-50": "#f8fafc",
|
|
@@ -36,9 +36,9 @@ module.exports = {
|
|
|
36
36
|
200: "#bae6fd",
|
|
37
37
|
300: "#7dd3fc",
|
|
38
38
|
400: "#38bdf8",
|
|
39
|
-
500: "
|
|
40
|
-
600: "
|
|
41
|
-
700: "
|
|
39
|
+
500: "var(--ews-primary, #21596c)",
|
|
40
|
+
600: "var(--ews-primary-hover, #1a4756)",
|
|
41
|
+
700: "var(--ews-primary-hover, #1a4756)",
|
|
42
42
|
800: "#0f2d36",
|
|
43
43
|
900: "#0a1f26",
|
|
44
44
|
},
|
|
@@ -48,8 +48,8 @@ module.exports = {
|
|
|
48
48
|
200: "#99f6e4",
|
|
49
49
|
300: "#5eead4",
|
|
50
50
|
400: "#2dd4bf",
|
|
51
|
-
500: "
|
|
52
|
-
600: "
|
|
51
|
+
500: "var(--ews-secondary, #3ba1a1)",
|
|
52
|
+
600: "var(--ews-secondary-hover, #308181)",
|
|
53
53
|
700: "#0f766e",
|
|
54
54
|
800: "#115e59",
|
|
55
55
|
900: "#134e4a",
|
|
@@ -60,8 +60,8 @@ module.exports = {
|
|
|
60
60
|
200: "#bbf7d0",
|
|
61
61
|
300: "#86efac",
|
|
62
62
|
400: "#4ade80",
|
|
63
|
-
500: "
|
|
64
|
-
600: "
|
|
63
|
+
500: "var(--ews-success, #059669)",
|
|
64
|
+
600: "var(--ews-success-hover, #047857)",
|
|
65
65
|
700: "#15803d",
|
|
66
66
|
800: "#166534",
|
|
67
67
|
900: "#14532d",
|
|
@@ -72,8 +72,8 @@ module.exports = {
|
|
|
72
72
|
200: "#fde68a",
|
|
73
73
|
300: "#fcd34d",
|
|
74
74
|
400: "#fbbf24",
|
|
75
|
-
500: "
|
|
76
|
-
600: "
|
|
75
|
+
500: "var(--ews-warning, #d97706)",
|
|
76
|
+
600: "var(--ews-warning-hover, #b45309)",
|
|
77
77
|
700: "#b45309",
|
|
78
78
|
800: "#92400e",
|
|
79
79
|
900: "#78350f",
|
|
@@ -84,8 +84,8 @@ module.exports = {
|
|
|
84
84
|
200: "#fecaca",
|
|
85
85
|
300: "#fca5a5",
|
|
86
86
|
400: "#f87171",
|
|
87
|
-
500: "
|
|
88
|
-
600: "
|
|
87
|
+
500: "var(--ews-error, #dc2626)",
|
|
88
|
+
600: "var(--ews-error-hover, #b91c1c)",
|
|
89
89
|
700: "#b91c1c",
|
|
90
90
|
800: "#991b1b",
|
|
91
91
|
900: "#7f1d1d",
|