@qwickapps/react-framework 1.5.6 → 1.5.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/dist/components/QwickApp.d.ts.map +1 -1
- package/dist/contexts/NavigationContext.d.ts.map +1 -1
- package/dist/hooks/useBaseProps.d.ts +12 -1161
- package/dist/hooks/useBaseProps.d.ts.map +1 -1
- package/dist/index.esm.js +387 -232
- package/dist/index.js +385 -230
- package/dist/palettes/manifest.json +19 -19
- package/dist/palettes/palette-autumn.1.4.9.css +172 -0
- package/dist/palettes/palette-autumn.1.4.9.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.0.css +172 -0
- package/dist/palettes/palette-autumn.1.5.0.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.1.css +172 -0
- package/dist/palettes/palette-autumn.1.5.1.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.2.css +172 -0
- package/dist/palettes/palette-autumn.1.5.2.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.3.css +172 -0
- package/dist/palettes/palette-autumn.1.5.3.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.4.css +172 -0
- package/dist/palettes/palette-autumn.1.5.4.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.5.css +172 -0
- package/dist/palettes/palette-autumn.1.5.5.min.css +1 -0
- package/dist/palettes/palette-autumn.1.5.7.css +172 -0
- package/dist/palettes/palette-autumn.1.5.7.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.4.9.css +172 -0
- package/dist/palettes/palette-cosmic.1.4.9.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.0.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.0.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.1.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.1.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.2.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.2.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.3.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.3.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.4.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.4.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.5.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.5.min.css +1 -0
- package/dist/palettes/palette-cosmic.1.5.7.css +172 -0
- package/dist/palettes/palette-cosmic.1.5.7.min.css +1 -0
- package/dist/palettes/palette-default.1.4.9.css +178 -0
- package/dist/palettes/palette-default.1.4.9.min.css +1 -0
- package/dist/palettes/palette-default.1.5.0.css +178 -0
- package/dist/palettes/palette-default.1.5.0.min.css +1 -0
- package/dist/palettes/palette-default.1.5.1.css +178 -0
- package/dist/palettes/palette-default.1.5.1.min.css +1 -0
- package/dist/palettes/palette-default.1.5.2.css +178 -0
- package/dist/palettes/palette-default.1.5.2.min.css +1 -0
- package/dist/palettes/palette-default.1.5.3.css +178 -0
- package/dist/palettes/palette-default.1.5.3.min.css +1 -0
- package/dist/palettes/palette-default.1.5.4.css +178 -0
- package/dist/palettes/palette-default.1.5.4.min.css +1 -0
- package/dist/palettes/palette-default.1.5.5.css +178 -0
- package/dist/palettes/palette-default.1.5.5.min.css +1 -0
- package/dist/palettes/palette-default.1.5.7.css +178 -0
- package/dist/palettes/palette-default.1.5.7.min.css +1 -0
- package/dist/palettes/palette-ocean.1.4.9.css +172 -0
- package/dist/palettes/palette-ocean.1.4.9.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.0.css +172 -0
- package/dist/palettes/palette-ocean.1.5.0.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.1.css +172 -0
- package/dist/palettes/palette-ocean.1.5.1.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.2.css +172 -0
- package/dist/palettes/palette-ocean.1.5.2.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.3.css +172 -0
- package/dist/palettes/palette-ocean.1.5.3.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.4.css +172 -0
- package/dist/palettes/palette-ocean.1.5.4.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.5.css +172 -0
- package/dist/palettes/palette-ocean.1.5.5.min.css +1 -0
- package/dist/palettes/palette-ocean.1.5.7.css +172 -0
- package/dist/palettes/palette-ocean.1.5.7.min.css +1 -0
- package/dist/palettes/palette-spring.1.4.9.css +160 -0
- package/dist/palettes/palette-spring.1.4.9.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.0.css +160 -0
- package/dist/palettes/palette-spring.1.5.0.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.1.css +160 -0
- package/dist/palettes/palette-spring.1.5.1.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.2.css +160 -0
- package/dist/palettes/palette-spring.1.5.2.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.3.css +166 -0
- package/dist/palettes/palette-spring.1.5.3.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.4.css +166 -0
- package/dist/palettes/palette-spring.1.5.4.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.5.css +166 -0
- package/dist/palettes/palette-spring.1.5.5.min.css +1 -0
- package/dist/palettes/palette-spring.1.5.7.css +166 -0
- package/dist/palettes/palette-spring.1.5.7.min.css +1 -0
- package/dist/palettes/palette-winter.1.4.9.css +172 -0
- package/dist/palettes/palette-winter.1.4.9.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.0.css +172 -0
- package/dist/palettes/palette-winter.1.5.0.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.1.css +172 -0
- package/dist/palettes/palette-winter.1.5.1.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.2.css +172 -0
- package/dist/palettes/palette-winter.1.5.2.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.3.css +172 -0
- package/dist/palettes/palette-winter.1.5.3.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.4.css +172 -0
- package/dist/palettes/palette-winter.1.5.4.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.5.css +172 -0
- package/dist/palettes/palette-winter.1.5.5.min.css +1 -0
- package/dist/palettes/palette-winter.1.5.7.css +172 -0
- package/dist/palettes/palette-winter.1.5.7.min.css +1 -0
- package/dist/utils/iconMap.d.ts +21 -8
- package/dist/utils/iconMap.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/utils/iconMap.test.tsx +197 -0
- package/src/components/QwickApp.tsx +8 -1
- package/src/contexts/NavigationContext.tsx +21 -15
- package/src/utils/iconMap.tsx +209 -153
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Winter Color Palette
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Cool blues, icy whites, and frosty grays - inspired by winter landscapes
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* ===== WINTER PALETTE - LIGHT THEME ===== */
|
|
10
|
+
html[data-palette="winter"]:not([data-theme="dark"]),
|
|
11
|
+
html[data-palette="winter"][data-theme="light"] {
|
|
12
|
+
/* Primary palette - Ice blue */
|
|
13
|
+
--palette-primary-main: #0077be;
|
|
14
|
+
--palette-primary-light: #5ba3d0;
|
|
15
|
+
--palette-primary-dark: #005082;
|
|
16
|
+
--palette-on-primary: #ffffff;
|
|
17
|
+
|
|
18
|
+
/* Secondary palette - Steel blue */
|
|
19
|
+
--palette-secondary-main: #4682b4;
|
|
20
|
+
--palette-secondary-light: #7ba7cc;
|
|
21
|
+
--palette-secondary-dark: #2e5984;
|
|
22
|
+
--palette-on-secondary: #ffffff;
|
|
23
|
+
|
|
24
|
+
/* Surface palette - Snow white */
|
|
25
|
+
--palette-surface-main: #fafbfc;
|
|
26
|
+
--palette-surface-variant: #e2e8f0; /* Improved contrast with cooler tone */
|
|
27
|
+
--palette-surface-elevated: #ffffff;
|
|
28
|
+
--palette-on-surface: #0f172a;
|
|
29
|
+
|
|
30
|
+
/* Background palette - Frosty */
|
|
31
|
+
--palette-background-main: #f8fafc;
|
|
32
|
+
--palette-background-dark: #f1f5f9;
|
|
33
|
+
--palette-background-overlay: rgba(248, 250, 252, 0.95);
|
|
34
|
+
--palette-on-background: #475569;
|
|
35
|
+
|
|
36
|
+
/* Header background with transparency */
|
|
37
|
+
--palette-header-bg-start: rgba(248, 250, 252, 0.98);
|
|
38
|
+
--palette-header-bg-end: rgba(248, 250, 252, 0.95);
|
|
39
|
+
--palette-header-collapsed-bg-start: rgba(248, 250, 252, 0.99);
|
|
40
|
+
--palette-header-collapsed-bg-end: rgba(248, 250, 252, 0.96);
|
|
41
|
+
|
|
42
|
+
/* Text palette - Winter tones */
|
|
43
|
+
--palette-text-primary: #0f172a;
|
|
44
|
+
--palette-text-secondary: #475569;
|
|
45
|
+
--palette-text-disabled: rgba(15, 23, 42, 0.38);
|
|
46
|
+
--palette-text-inverted: #ffffff;
|
|
47
|
+
|
|
48
|
+
/* Border palette - Icy */
|
|
49
|
+
--palette-border-main: #cbd5e1;
|
|
50
|
+
--palette-border-light: rgba(15, 23, 42, 0.12);
|
|
51
|
+
--palette-border-lighter: rgba(15, 23, 42, 0.05);
|
|
52
|
+
--palette-border-medium: #94a3b8;
|
|
53
|
+
|
|
54
|
+
/* Success palette - Pine green */
|
|
55
|
+
--palette-success-main: #059669;
|
|
56
|
+
--palette-success-light: #d1fae5;
|
|
57
|
+
--palette-success-dark: #064e3b;
|
|
58
|
+
--palette-success-border: #a7f3d0;
|
|
59
|
+
|
|
60
|
+
/* Error palette - Winter berry */
|
|
61
|
+
--palette-error-main: #dc2626;
|
|
62
|
+
--palette-error-light: #fee2e2;
|
|
63
|
+
--palette-error-dark: #7f1d1d;
|
|
64
|
+
--palette-error-border: #fecaca;
|
|
65
|
+
|
|
66
|
+
/* Warning palette - Amber frost */
|
|
67
|
+
--palette-warning-main: #d97706;
|
|
68
|
+
--palette-warning-light: #fef3c7;
|
|
69
|
+
--palette-warning-dark: #92400e;
|
|
70
|
+
--palette-warning-border: #fde68a;
|
|
71
|
+
|
|
72
|
+
/* Info palette - Arctic blue */
|
|
73
|
+
--palette-info-main: #0284c7;
|
|
74
|
+
--palette-info-light: #e0f2fe;
|
|
75
|
+
--palette-info-dark: #0c4a6e;
|
|
76
|
+
--palette-on-info: #ffffff;
|
|
77
|
+
--palette-info-border: #7dd3fc;
|
|
78
|
+
|
|
79
|
+
/* Accent palette - Aurora colors */
|
|
80
|
+
--palette-accent-main: #ec4899;
|
|
81
|
+
--palette-accent-light: #fce7f3;
|
|
82
|
+
--palette-accent-dark: #be185d;
|
|
83
|
+
--palette-on-accent: #ffffff;
|
|
84
|
+
|
|
85
|
+
/* Control palette - Charcoal */
|
|
86
|
+
--palette-control-main: #1e293b;
|
|
87
|
+
--palette-control-light: #334155;
|
|
88
|
+
--palette-control-text: #e2e8f0;
|
|
89
|
+
--palette-control-border: #475569;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* ===== WINTER PALETTE - DARK THEME ===== */
|
|
93
|
+
html[data-palette="winter"][data-theme="dark"] {
|
|
94
|
+
/* Primary palette - Arctic glow */
|
|
95
|
+
--palette-primary-main: #7dd3fc;
|
|
96
|
+
--palette-primary-light: #bae6fd;
|
|
97
|
+
--palette-primary-dark: #0369a1;
|
|
98
|
+
--palette-on-primary: #020617;
|
|
99
|
+
|
|
100
|
+
/* Secondary palette - Moonlight */
|
|
101
|
+
--palette-secondary-main: #94a3b8;
|
|
102
|
+
--palette-secondary-light: #cbd5e1;
|
|
103
|
+
--palette-secondary-dark: #64748b;
|
|
104
|
+
--palette-on-secondary: #020617;
|
|
105
|
+
|
|
106
|
+
/* Surface palette - Dark frost */
|
|
107
|
+
--palette-surface-main: #172033;
|
|
108
|
+
--palette-surface-variant: #1e293b;
|
|
109
|
+
--palette-surface-elevated: #334155;
|
|
110
|
+
--palette-on-surface: #f8fafc;
|
|
111
|
+
|
|
112
|
+
/* Background palette - Winter night */
|
|
113
|
+
--palette-background-main: #04080f;
|
|
114
|
+
--palette-background-dark: #0a1018;
|
|
115
|
+
--palette-background-overlay: rgba(15, 23, 42, 0.95);
|
|
116
|
+
--palette-on-background: #cbd5e1;
|
|
117
|
+
|
|
118
|
+
/* Header background with transparency */
|
|
119
|
+
--palette-header-bg-start: rgba(4, 8, 15, 0.98);
|
|
120
|
+
--palette-header-bg-end: rgba(4, 8, 15, 0.95);
|
|
121
|
+
--palette-header-collapsed-bg-start: rgba(4, 8, 15, 0.99);
|
|
122
|
+
--palette-header-collapsed-bg-end: rgba(4, 8, 15, 0.96);
|
|
123
|
+
|
|
124
|
+
/* Text palette - Snow and ice */
|
|
125
|
+
--palette-text-primary: #f8fafc;
|
|
126
|
+
--palette-text-secondary: #cbd5e1;
|
|
127
|
+
--palette-text-disabled: rgba(248, 250, 252, 0.38);
|
|
128
|
+
--palette-text-inverted: #020617;
|
|
129
|
+
|
|
130
|
+
/* Border palette - Dark ice */
|
|
131
|
+
--palette-border-main: #475569;
|
|
132
|
+
--palette-border-light: rgba(248, 250, 252, 0.12);
|
|
133
|
+
--palette-border-lighter: rgba(248, 250, 252, 0.05);
|
|
134
|
+
--palette-border-medium: #334155;
|
|
135
|
+
|
|
136
|
+
/* Success palette - Aurora green */
|
|
137
|
+
--palette-success-main: #34d399;
|
|
138
|
+
--palette-success-light: #064e3b;
|
|
139
|
+
--palette-success-dark: #10b981;
|
|
140
|
+
--palette-success-border: #065f46;
|
|
141
|
+
|
|
142
|
+
/* Error palette - Northern lights red */
|
|
143
|
+
--palette-error-main: #f87171;
|
|
144
|
+
--palette-error-light: #7f1d1d;
|
|
145
|
+
--palette-error-dark: #ef4444;
|
|
146
|
+
--palette-error-border: #991b1b;
|
|
147
|
+
|
|
148
|
+
/* Warning palette - Aurora orange */
|
|
149
|
+
--palette-warning-main: #fb923c;
|
|
150
|
+
--palette-warning-light: #9a3412;
|
|
151
|
+
--palette-warning-dark: #f97316;
|
|
152
|
+
--palette-warning-border: #c2410c;
|
|
153
|
+
|
|
154
|
+
/* Info palette - Polar blue */
|
|
155
|
+
--palette-info-main: #38bdf8;
|
|
156
|
+
--palette-info-light: #0c4a6e;
|
|
157
|
+
--palette-info-dark: #0ea5e9;
|
|
158
|
+
--palette-on-info: #020617;
|
|
159
|
+
--palette-info-border: #0284c7;
|
|
160
|
+
|
|
161
|
+
/* Accent palette - Northern lights */
|
|
162
|
+
--palette-accent-main: #f472b6;
|
|
163
|
+
--palette-accent-light: #fce7f3;
|
|
164
|
+
--palette-accent-dark: #db2777;
|
|
165
|
+
--palette-on-accent: #f8fafc;
|
|
166
|
+
|
|
167
|
+
/* Control palette - Midnight */
|
|
168
|
+
--palette-control-main: #1e293b;
|
|
169
|
+
--palette-control-light: #334155;
|
|
170
|
+
--palette-control-text: #e2e8f0;
|
|
171
|
+
--palette-control-border: #475569;
|
|
172
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
html[data-palette="winter"]:not([data-theme="dark"]),html[data-palette="winter"][data-theme="light"]{--palette-primary-main:#0077be;--palette-primary-light:#5ba3d0;--palette-primary-dark:#005082;--palette-on-primary:#ffffff;--palette-secondary-main:#4682b4;--palette-secondary-light:#7ba7cc;--palette-secondary-dark:#2e5984;--palette-on-secondary:#ffffff;--palette-surface-main:#fafbfc;--palette-surface-variant:#e2e8f0;--palette-surface-elevated:#ffffff;--palette-on-surface:#0f172a;--palette-background-main:#f8fafc;--palette-background-dark:#f1f5f9;--palette-background-overlay:rgba(248,250,252,0.95);--palette-on-background:#475569;--palette-header-bg-start:rgba(248,250,252,0.98);--palette-header-bg-end:rgba(248,250,252,0.95);--palette-header-collapsed-bg-start:rgba(248,250,252,0.99);--palette-header-collapsed-bg-end:rgba(248,250,252,0.96);--palette-text-primary:#0f172a;--palette-text-secondary:#475569;--palette-text-disabled:rgba(15,23,42,0.38);--palette-text-inverted:#ffffff;--palette-border-main:#cbd5e1;--palette-border-light:rgba(15,23,42,0.12);--palette-border-lighter:rgba(15,23,42,0.05);--palette-border-medium:#94a3b8;--palette-success-main:#059669;--palette-success-light:#d1fae5;--palette-success-dark:#064e3b;--palette-success-border:#a7f3d0;--palette-error-main:#dc2626;--palette-error-light:#fee2e2;--palette-error-dark:#7f1d1d;--palette-error-border:#fecaca;--palette-warning-main:#d97706;--palette-warning-light:#fef3c7;--palette-warning-dark:#92400e;--palette-warning-border:#fde68a;--palette-info-main:#0284c7;--palette-info-light:#e0f2fe;--palette-info-dark:#0c4a6e;--palette-on-info:#ffffff;--palette-info-border:#7dd3fc;--palette-accent-main:#ec4899;--palette-accent-light:#fce7f3;--palette-accent-dark:#be185d;--palette-on-accent:#ffffff;--palette-control-main:#1e293b;--palette-control-light:#334155;--palette-control-text:#e2e8f0;--palette-control-border:#475569}html[data-palette="winter"][data-theme="dark"]{--palette-primary-main:#7dd3fc;--palette-primary-light:#bae6fd;--palette-primary-dark:#0369a1;--palette-on-primary:#020617;--palette-secondary-main:#94a3b8;--palette-secondary-light:#cbd5e1;--palette-secondary-dark:#64748b;--palette-on-secondary:#020617;--palette-surface-main:#172033;--palette-surface-variant:#1e293b;--palette-surface-elevated:#334155;--palette-on-surface:#f8fafc;--palette-background-main:#04080f;--palette-background-dark:#0a1018;--palette-background-overlay:rgba(15,23,42,0.95);--palette-on-background:#cbd5e1;--palette-header-bg-start:rgba(4,8,15,0.98);--palette-header-bg-end:rgba(4,8,15,0.95);--palette-header-collapsed-bg-start:rgba(4,8,15,0.99);--palette-header-collapsed-bg-end:rgba(4,8,15,0.96);--palette-text-primary:#f8fafc;--palette-text-secondary:#cbd5e1;--palette-text-disabled:rgba(248,250,252,0.38);--palette-text-inverted:#020617;--palette-border-main:#475569;--palette-border-light:rgba(248,250,252,0.12);--palette-border-lighter:rgba(248,250,252,0.05);--palette-border-medium:#334155;--palette-success-main:#34d399;--palette-success-light:#064e3b;--palette-success-dark:#10b981;--palette-success-border:#065f46;--palette-error-main:#f87171;--palette-error-light:#7f1d1d;--palette-error-dark:#ef4444;--palette-error-border:#991b1b;--palette-warning-main:#fb923c;--palette-warning-light:#9a3412;--palette-warning-dark:#f97316;--palette-warning-border:#c2410c;--palette-info-main:#38bdf8;--palette-info-light:#0c4a6e;--palette-info-dark:#0ea5e9;--palette-on-info:#020617;--palette-info-border:#0284c7;--palette-accent-main:#f472b6;--palette-accent-light:#fce7f3;--palette-accent-dark:#db2777;--palette-on-accent:#f8fafc;--palette-control-main:#1e293b;--palette-control-light:#334155;--palette-control-text:#e2e8f0;--palette-control-border:#475569}
|
package/dist/utils/iconMap.d.ts
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* Provides centralized icon mapping for both Material-UI components and emoji representations.
|
|
5
5
|
* Used across the framework for consistent icon rendering in buttons, navigation, admin UI, etc.
|
|
6
6
|
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Static map for commonly used icons with emoji support
|
|
9
|
+
* - Fallback to HelpOutline icon for unmapped icons (with console warning)
|
|
10
|
+
* - Runtime icon registration via registerIcon() for app-specific icons
|
|
11
|
+
*
|
|
7
12
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
13
|
*/
|
|
9
14
|
import React from 'react';
|
|
@@ -15,21 +20,28 @@ export interface IconMapping {
|
|
|
15
20
|
component: React.ComponentType;
|
|
16
21
|
}
|
|
17
22
|
/**
|
|
18
|
-
* Centralized icon registry mapping icon names to their representations
|
|
19
|
-
*
|
|
23
|
+
* Centralized icon registry mapping icon names to their representations.
|
|
24
|
+
* Sorted alphabetically by category, then by key within each category.
|
|
25
|
+
*
|
|
26
|
+
* For icons not in this map, getIconComponent() will return a HelpOutline fallback
|
|
27
|
+
* and log a warning. Use registerIcon() to add app-specific icons at runtime.
|
|
20
28
|
*/
|
|
21
29
|
export declare const iconMap: Record<string, IconMapping>;
|
|
22
30
|
/**
|
|
23
31
|
* Get emoji representation of an icon
|
|
24
|
-
* @param iconName - Icon name (case-insensitive)
|
|
32
|
+
* @param iconName - Icon name (case-insensitive, supports snake_case)
|
|
25
33
|
* @param fallback - Fallback emoji if icon not found (default: 🔗)
|
|
26
34
|
* @returns Emoji string
|
|
27
35
|
*/
|
|
28
36
|
export declare function getIconEmoji(iconName: string | undefined, fallback?: string): string;
|
|
29
37
|
/**
|
|
30
|
-
* Get Material-UI component representation of an icon
|
|
31
|
-
*
|
|
32
|
-
*
|
|
38
|
+
* Get Material-UI component representation of an icon.
|
|
39
|
+
*
|
|
40
|
+
* Uses the static iconMap for known icons. For unmapped icons,
|
|
41
|
+
* returns a HelpOutline fallback and logs a warning.
|
|
42
|
+
*
|
|
43
|
+
* @param iconName - Icon name (case-insensitive, supports snake_case)
|
|
44
|
+
* @returns React element (mapped icon or HelpOutline fallback), or null if no name provided
|
|
33
45
|
*/
|
|
34
46
|
export declare function getIconComponent(iconName: string | undefined): React.ReactElement | null;
|
|
35
47
|
/**
|
|
@@ -38,11 +50,12 @@ export declare function getIconComponent(iconName: string | undefined): React.Re
|
|
|
38
50
|
*/
|
|
39
51
|
export declare function registerIcon(name: string, mapping: IconMapping): void;
|
|
40
52
|
/**
|
|
41
|
-
* Check if an icon is registered
|
|
53
|
+
* Check if an icon is registered in the static map
|
|
54
|
+
* If false, getIconComponent will return HelpOutline fallback
|
|
42
55
|
*/
|
|
43
56
|
export declare function hasIcon(iconName: string): boolean;
|
|
44
57
|
/**
|
|
45
|
-
* Get all registered icon names
|
|
58
|
+
* Get all registered icon names from the static map
|
|
46
59
|
*/
|
|
47
60
|
export declare function getRegisteredIcons(): string[];
|
|
48
61
|
//# sourceMappingURL=iconMap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconMap.d.ts","sourceRoot":"","sources":["../../src/utils/iconMap.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"iconMap.d.ts","sourceRoot":"","sources":["../../src/utils/iconMap.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAsF1B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;CAChC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA0H/C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAE,MAAa,GAAG,MAAM,CAK1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAiBxF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAErE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qwickapps/react-framework",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Complete React framework with responsive navigation, flexible layouts, theming system, and reusable components for building modern applications.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon Map Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the icon mapping utility functions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getIconComponent,
|
|
9
|
+
getIconEmoji,
|
|
10
|
+
hasIcon,
|
|
11
|
+
registerIcon,
|
|
12
|
+
getRegisteredIcons,
|
|
13
|
+
iconMap,
|
|
14
|
+
} from '../../utils/iconMap';
|
|
15
|
+
import { Home, Star } from '@mui/icons-material';
|
|
16
|
+
|
|
17
|
+
describe('iconMap', () => {
|
|
18
|
+
describe('getIconComponent', () => {
|
|
19
|
+
it('returns null for undefined input', () => {
|
|
20
|
+
expect(getIconComponent(undefined)).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('returns null for empty string', () => {
|
|
24
|
+
expect(getIconComponent('')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns correct component for mapped icon', () => {
|
|
28
|
+
const result = getIconComponent('home');
|
|
29
|
+
expect(result).not.toBeNull();
|
|
30
|
+
expect(result?.type).toBe(Home);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('is case-insensitive', () => {
|
|
34
|
+
const lower = getIconComponent('home');
|
|
35
|
+
const upper = getIconComponent('HOME');
|
|
36
|
+
const mixed = getIconComponent('Home');
|
|
37
|
+
|
|
38
|
+
expect(lower?.type).toBe(upper?.type);
|
|
39
|
+
expect(lower?.type).toBe(mixed?.type);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('supports snake_case icon names', () => {
|
|
43
|
+
const result = getIconComponent('manage_accounts');
|
|
44
|
+
expect(result).not.toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns HelpOutline fallback for unmapped icons', () => {
|
|
48
|
+
// Suppress console.warn for this test
|
|
49
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
50
|
+
|
|
51
|
+
const result = getIconComponent('nonexistent_icon_xyz');
|
|
52
|
+
expect(result).not.toBeNull();
|
|
53
|
+
|
|
54
|
+
warnSpy.mockRestore();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('logs warning for unmapped icons in non-production', () => {
|
|
58
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
59
|
+
|
|
60
|
+
getIconComponent('nonexistent_icon_xyz');
|
|
61
|
+
|
|
62
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
63
|
+
expect.stringContaining('nonexistent_icon_xyz')
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
warnSpy.mockRestore();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('getIconEmoji', () => {
|
|
71
|
+
it('returns fallback for undefined input', () => {
|
|
72
|
+
expect(getIconEmoji(undefined)).toBe('🔗');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('returns custom fallback when provided', () => {
|
|
76
|
+
expect(getIconEmoji(undefined, '❓')).toBe('❓');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('returns correct emoji for mapped icon', () => {
|
|
80
|
+
expect(getIconEmoji('home')).toBe('🏠');
|
|
81
|
+
expect(getIconEmoji('favorite')).toBe('❤️');
|
|
82
|
+
expect(getIconEmoji('star')).toBe('⭐');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('is case-insensitive', () => {
|
|
86
|
+
expect(getIconEmoji('HOME')).toBe(getIconEmoji('home'));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('returns fallback for unmapped icons', () => {
|
|
90
|
+
expect(getIconEmoji('nonexistent_icon')).toBe('🔗');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('hasIcon', () => {
|
|
95
|
+
it('returns true for mapped icons', () => {
|
|
96
|
+
expect(hasIcon('home')).toBe(true);
|
|
97
|
+
expect(hasIcon('settings')).toBe(true);
|
|
98
|
+
expect(hasIcon('people')).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('returns false for unmapped icons', () => {
|
|
102
|
+
expect(hasIcon('nonexistent_icon')).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('is case-insensitive', () => {
|
|
106
|
+
expect(hasIcon('HOME')).toBe(true);
|
|
107
|
+
expect(hasIcon('Home')).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('registerIcon', () => {
|
|
112
|
+
// Cleanup any test icons after each test to prevent pollution
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
delete iconMap['custom_test_icon'];
|
|
115
|
+
delete iconMap['upper_case_icon'];
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('registers new icons at runtime', () => {
|
|
119
|
+
const customIconName = 'custom_test_icon';
|
|
120
|
+
|
|
121
|
+
// Should not exist initially
|
|
122
|
+
expect(hasIcon(customIconName)).toBe(false);
|
|
123
|
+
|
|
124
|
+
// Register it
|
|
125
|
+
registerIcon(customIconName, {
|
|
126
|
+
emoji: '🎯',
|
|
127
|
+
component: Star,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Should exist now
|
|
131
|
+
expect(hasIcon(customIconName)).toBe(true);
|
|
132
|
+
expect(getIconEmoji(customIconName)).toBe('🎯');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('is case-insensitive for registration', () => {
|
|
136
|
+
registerIcon('UPPER_CASE_ICON', {
|
|
137
|
+
emoji: '🔤',
|
|
138
|
+
component: Star,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
expect(hasIcon('upper_case_icon')).toBe(true);
|
|
142
|
+
expect(hasIcon('UPPER_CASE_ICON')).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('getRegisteredIcons', () => {
|
|
147
|
+
it('returns an array of icon names', () => {
|
|
148
|
+
const icons = getRegisteredIcons();
|
|
149
|
+
|
|
150
|
+
expect(Array.isArray(icons)).toBe(true);
|
|
151
|
+
expect(icons.length).toBeGreaterThan(0);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('includes common icons', () => {
|
|
155
|
+
const icons = getRegisteredIcons();
|
|
156
|
+
|
|
157
|
+
expect(icons).toContain('home');
|
|
158
|
+
expect(icons).toContain('settings');
|
|
159
|
+
expect(icons).toContain('dashboard');
|
|
160
|
+
expect(icons).toContain('people');
|
|
161
|
+
expect(icons).toContain('manage_accounts');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('iconMap coverage', () => {
|
|
166
|
+
it('has emoji and component for all entries', () => {
|
|
167
|
+
for (const [name, mapping] of Object.entries(iconMap)) {
|
|
168
|
+
expect(mapping.emoji).toBeDefined();
|
|
169
|
+
expect(typeof mapping.emoji).toBe('string');
|
|
170
|
+
expect(mapping.emoji.length).toBeGreaterThan(0);
|
|
171
|
+
|
|
172
|
+
expect(mapping.component).toBeDefined();
|
|
173
|
+
// Components can be functions or objects (React.memo, forwardRef, etc.)
|
|
174
|
+
expect(['function', 'object']).toContain(typeof mapping.component);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('includes essential icons for navigation', () => {
|
|
179
|
+
const essentialIcons = [
|
|
180
|
+
'home', 'dashboard', 'settings', 'menu',
|
|
181
|
+
'people', 'person', 'help', 'info',
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
for (const icon of essentialIcons) {
|
|
185
|
+
expect(hasIcon(icon)).toBe(true);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('includes authentication icons', () => {
|
|
190
|
+
const authIcons = ['lock', 'security', 'key', 'login', 'logout'];
|
|
191
|
+
|
|
192
|
+
for (const icon of authIcons) {
|
|
193
|
+
expect(hasIcon(icon)).toBe(true);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
36
36
|
*/
|
|
37
|
-
import React, { cloneElement, useState } from 'react';
|
|
37
|
+
import React, { cloneElement, useState, useEffect } from 'react';
|
|
38
38
|
import { DataProvider, ThemeProvider, PrintModeProvider, NavigationProvider, type ThemeMode } from '../contexts';
|
|
39
39
|
import { QwickAppContext, type QwickAppContextValue, type QwickAppProps } from '../contexts/QwickAppContext';
|
|
40
40
|
import { type TemplateResolverConfig } from '../types';
|
|
@@ -126,6 +126,13 @@ export const QwickApp: React.FC<QwickAppComponentProps> = ({
|
|
|
126
126
|
setAppConfig(prev => ({ ...prev, ...updates } as typeof prev));
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
// Sync logo prop changes with internal state (for dynamic logo updates)
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (resolvedConfig.logo !== appConfig.logo) {
|
|
132
|
+
setAppConfig(prev => ({ ...prev, logo: resolvedConfig.logo }));
|
|
133
|
+
}
|
|
134
|
+
}, [resolvedConfig.logo]);
|
|
135
|
+
|
|
129
136
|
const contextValue: QwickAppContextValue = {
|
|
130
137
|
appName: resolvedConfig.appName!, // Safe to use ! since we validated above
|
|
131
138
|
appId: resolvedConfig.appId,
|
|
@@ -15,7 +15,7 @@ import { createContext, useContext, type ReactNode } from 'react';
|
|
|
15
15
|
import {
|
|
16
16
|
useNavigate,
|
|
17
17
|
useLocation,
|
|
18
|
-
|
|
18
|
+
useInRouterContext,
|
|
19
19
|
} from 'react-router-dom';
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -58,17 +58,23 @@ function ReactRouterNavigationProvider({ children }: { children: ReactNode }) {
|
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
// Defensive check for location - fall back to window.location if React Router's location is undefined
|
|
62
|
+
const location: NavigationLocation | undefined = reactRouterLocation
|
|
63
|
+
? {
|
|
64
|
+
pathname: reactRouterLocation.pathname,
|
|
65
|
+
search: reactRouterLocation.search,
|
|
66
|
+
hash: reactRouterLocation.hash,
|
|
67
|
+
}
|
|
68
|
+
: typeof window !== 'undefined'
|
|
69
|
+
? {
|
|
70
|
+
pathname: window.location.pathname,
|
|
71
|
+
search: window.location.search,
|
|
72
|
+
hash: window.location.hash,
|
|
73
|
+
}
|
|
74
|
+
: undefined;
|
|
75
|
+
|
|
61
76
|
return (
|
|
62
|
-
<NavigationContext.Provider
|
|
63
|
-
value={{
|
|
64
|
-
navigate,
|
|
65
|
-
location: {
|
|
66
|
-
pathname: reactRouterLocation.pathname,
|
|
67
|
-
search: reactRouterLocation.search,
|
|
68
|
-
hash: reactRouterLocation.hash,
|
|
69
|
-
},
|
|
70
|
-
}}
|
|
71
|
-
>
|
|
77
|
+
<NavigationContext.Provider value={{ navigate, location }}>
|
|
72
78
|
{children}
|
|
73
79
|
</NavigationContext.Provider>
|
|
74
80
|
);
|
|
@@ -115,11 +121,11 @@ function FallbackNavigationProvider({ children }: { children: ReactNode }) {
|
|
|
115
121
|
* This is included automatically by QwickApp - you don't need to add it manually.
|
|
116
122
|
*/
|
|
117
123
|
export function NavigationProvider({ children }: { children: ReactNode }) {
|
|
118
|
-
// Check if we're inside a React Router
|
|
119
|
-
//
|
|
120
|
-
const
|
|
124
|
+
// Check if we're inside a React Router using the official hook
|
|
125
|
+
// This is more reliable than checking internal UNSAFE contexts
|
|
126
|
+
const isInRouter = useInRouterContext();
|
|
121
127
|
|
|
122
|
-
if (
|
|
128
|
+
if (isInRouter) {
|
|
123
129
|
// We're inside a Router, use React Router's navigation
|
|
124
130
|
return (
|
|
125
131
|
<ReactRouterNavigationProvider>{children}</ReactRouterNavigationProvider>
|