@sanvika/ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ export { B as BellIcon, C as ChevronDown, E as EmailIcon, F as FaAngleDown, a as FaAngleRight, b as FaArrowDown, c as FaArrowLeft, d as FaArrowUp, e as FaBell, f as FaBullhorn, g as FaCalendarAlt, h as FaCheck, i as FaCheckCircle, j as FaCheckDouble, k as FaChevronDown, l as FaChevronRight, m as FaCircle, n as FaComments, o as FaEye, p as FaEyeSlash, q as FaHome, r as FaKeyboard, s as FaLocationArrow, t as FaMapMarker, t as FaMapMarkerAlt, u as FaMoon, v as FaPaperPlane, w as FaPaperclip, x as FaSignInAlt, y as FaSmile, z as FaStar, z as FaStarButton, A as FaTag, D as FaThumbsDown, G as FaThumbsUp, H as FaTrash, I as FaUser, J as FaUserCircle, I as FaUserIcon, K as FacebookIcon, L as HalfMoonIcon, M as HeartIcon, N as InstagramIcon, O as LinkedInIcon, P as MapMarkerIcon, Q as MdWbSunny, R as RefreshIcon, S as SearchIcon, T as StarIcon, R as SyncIcon, U as TelegramIcon, V as TwitterIcon, W as UserIcon, X as WhatsappIcon, Y as YoutubeIcon } from '../EmailIcon-ssF1iAVu.js';
3
+ import 'react';
4
+ import 'react/jsx-runtime';
package/dist/index.js ADDED
@@ -0,0 +1,583 @@
1
+ "use client";
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import { useEffect, useSyncExternalStore, useState, useRef, useCallback, useContext, createContext } from 'react';
4
+ import { M as HeartIcon, d as FaArrowUp, b as FaArrowDown } from './EmailIcon-ssF1iAVu.js';
5
+ export { B as BellIcon, C as ChevronDown, E as EmailIcon, F as FaAngleDown, a as FaAngleRight, c as FaArrowLeft, e as FaBell, f as FaBullhorn, g as FaCalendarAlt, h as FaCheck, i as FaCheckCircle, j as FaCheckDouble, k as FaChevronDown, l as FaChevronRight, m as FaCircle, n as FaComments, o as FaEye, p as FaEyeSlash, q as FaHome, r as FaKeyboard, s as FaLocationArrow, t as FaMapMarker, t as FaMapMarkerAlt, u as FaMoon, v as FaPaperPlane, w as FaPaperclip, x as FaSignInAlt, y as FaSmile, z as FaStar, z as FaStarButton, A as FaTag, D as FaThumbsDown, G as FaThumbsUp, H as FaTrash, I as FaUser, J as FaUserCircle, I as FaUserIcon, K as FacebookIcon, L as HalfMoonIcon, N as InstagramIcon, O as LinkedInIcon, P as MapMarkerIcon, Q as MdWbSunny, R as RefreshIcon, S as SearchIcon, T as StarIcon, R as SyncIcon, U as TelegramIcon, V as TwitterIcon, W as UserIcon, X as WhatsappIcon, Y as YoutubeIcon } from './EmailIcon-ssF1iAVu.js';
6
+ import { createPortal } from 'react-dom';
7
+
8
+ function styleInject(css, ref) {
9
+ if (ref === void 0) ref = {};
10
+ var insertAt = ref.insertAt;
11
+ if (!css || typeof document === 'undefined') {
12
+ return;
13
+ }
14
+ var head = document.head || document.getElementsByTagName('head')[0];
15
+ var style = document.createElement('style');
16
+ style.type = 'text/css';
17
+ if (insertAt === 'top') {
18
+ if (head.firstChild) {
19
+ head.insertBefore(style, head.firstChild);
20
+ } else {
21
+ head.appendChild(style);
22
+ }
23
+ } else {
24
+ head.appendChild(style);
25
+ }
26
+ if (style.styleSheet) {
27
+ style.styleSheet.cssText = css;
28
+ } else {
29
+ style.appendChild(document.createTextNode(css));
30
+ }
31
+ }
32
+
33
+ var css_248z$a = ".Navbar-module_navbar__2NTiG{align-items:center;background-color:var(--card-bg);border-bottom:1px solid var(--border-color);border-top:1px solid var(--border-color);box-shadow:0 2px 4px rgba(0,0,0,.1);column-gap:clamp(4px,1vw,12px);display:grid;grid-template-columns:auto 1fr auto;left:0;min-height:clamp(40px,10vw,60px);overflow:visible;padding:clamp(4px,1vw,10px) clamp(6px,2vw,18px);position:fixed;right:0;top:0;transition:background-color .3s ease;width:100%;z-index:1000}.Navbar-module_navSectionLeft__zH0WR{align-items:center;color:inherit;cursor:pointer;display:flex;height:100%;justify-content:flex-start;min-width:clamp(48px,16vw,88px);text-decoration:none;user-select:none}.Navbar-module_navSectionCenter__j0wpK{align-items:center;display:flex;height:100%;justify-content:center;min-width:0;width:100%}.Navbar-module_menu__QQfPq{align-items:center;display:flex;flex-wrap:nowrap;gap:clamp(4px,1.2vw,12px);justify-content:center;list-style:none;margin:0;padding:0;width:100%}.Navbar-module_navSectionRight__A4Egv{align-items:center;display:flex;height:100%;justify-content:flex-end;min-width:clamp(48px,16vw,88px);overflow:visible}";
34
+ var styles$a = {"navbar":"Navbar-module_navbar__2NTiG","navSectionLeft":"Navbar-module_navSectionLeft__zH0WR","navSectionCenter":"Navbar-module_navSectionCenter__j0wpK","menu":"Navbar-module_menu__QQfPq","navSectionRight":"Navbar-module_navSectionRight__A4Egv"};
35
+ styleInject(css_248z$a);
36
+
37
+ // src/components/layout/Navbar.jsx
38
+ const Navbar = ({
39
+ leftSlot,
40
+ centerSlot,
41
+ rightSlot,
42
+ className = "",
43
+ ariaLabel = "Main navigation"
44
+ }) => {
45
+ return /*#__PURE__*/jsxs("nav", {
46
+ className: `${styles$a.navbar} ${className}`.trim(),
47
+ "aria-label": ariaLabel,
48
+ children: [/*#__PURE__*/jsx("div", {
49
+ className: styles$a.navSectionLeft,
50
+ children: leftSlot
51
+ }), /*#__PURE__*/jsx("div", {
52
+ className: styles$a.navSectionCenter,
53
+ children: centerSlot && /*#__PURE__*/jsx("ul", {
54
+ className: styles$a.menu,
55
+ children: centerSlot
56
+ })
57
+ }), /*#__PURE__*/jsx("div", {
58
+ className: styles$a.navSectionRight,
59
+ children: rightSlot
60
+ })]
61
+ });
62
+ };
63
+
64
+ var css_248z$9 = ".SubNavbar-module_subNavbar__1hd8N{align-items:center;background-color:var(--card-bg);border-bottom:.5px solid var(--border-color);box-shadow:0 2px 4px rgba(0,0,0,.1);display:flex;justify-content:center;left:0;min-height:clamp(48px,10vw,60px);overflow:visible;padding:clamp(6px,1.5vw,10px) clamp(6px,2vw,18px);position:fixed;right:0;top:clamp(48px,10vw,60px);transition:background-color .3s ease;width:100%;z-index:999}.SubNavbar-module_menu__ejJKq{align-items:center;display:flex;flex-wrap:nowrap;gap:clamp(4px,1.5vw,16px);justify-content:space-evenly;list-style:none;margin:0;max-width:500px;padding:0 clamp(4px,1vw,12px);width:100%}";
65
+ var styles$9 = {"subNavbar":"SubNavbar-module_subNavbar__1hd8N","menu":"SubNavbar-module_menu__ejJKq"};
66
+ styleInject(css_248z$9);
67
+
68
+ // src/components/layout/SubNavbar.jsx
69
+ const SubNavbar = ({
70
+ children,
71
+ afterContent,
72
+ className = "",
73
+ ariaLabel = "Secondary navigation"
74
+ }) => {
75
+ return /*#__PURE__*/jsxs(Fragment, {
76
+ children: [/*#__PURE__*/jsx("nav", {
77
+ className: `${styles$9.subNavbar} ${className}`.trim(),
78
+ "aria-label": ariaLabel,
79
+ children: /*#__PURE__*/jsx("ul", {
80
+ className: styles$9.menu,
81
+ children: children
82
+ })
83
+ }), afterContent]
84
+ });
85
+ };
86
+
87
+ var css_248z$8 = ".Footer-module_footer__1gTBc{background-color:var(--card-bg);border-bottom:clamp(.5px,.2vw,1px) solid var(--border-color);border-top:clamp(.5px,.2vw,1px) solid var(--border-color);box-shadow:0 -1px 0 0 var(--border-color) inset;display:flex;justify-content:center;min-height:clamp(24px,6vw,36px);padding:clamp(2px,.5vw,4px) clamp(5px,1.5vw,10px);position:relative;text-align:center;transition:background-color .3s ease,color .3s ease;width:100%;z-index:900}.Footer-module_footerContent__sC89p{align-items:center;display:flex;flex-direction:column;gap:clamp(1px,.2vw,2px);max-width:clamp(300px,90vw,400px);width:100%}.Footer-module_topLine__NNJXQ{align-items:center;display:flex;justify-content:center;width:100%}.Footer-module_socialIconsContainer__kNCBG{align-items:center;display:flex;flex:0 0 auto;justify-content:center;padding:clamp(2px,1vw,4px) clamp(4px,1.5vw,6px)}.Footer-module_socialIcons__O-HxQ{align-items:center;display:flex;gap:clamp(8px,2vw,16px);justify-content:center}.Footer-module_legalLinks__fJAsq{align-items:center;display:flex;flex-wrap:nowrap;gap:clamp(4px,1.5vw,8px);justify-content:center;width:100%}.Footer-module_dunsContainer__-mj-b{align-items:center;display:flex;justify-content:center;margin-top:clamp(2px,.5vw,4px);width:100%}";
88
+ var styles$8 = {"footer":"Footer-module_footer__1gTBc","footerContent":"Footer-module_footerContent__sC89p","topLine":"Footer-module_topLine__NNJXQ","socialIconsContainer":"Footer-module_socialIconsContainer__kNCBG","socialIcons":"Footer-module_socialIcons__O-HxQ","legalLinks":"Footer-module_legalLinks__fJAsq","dunsContainer":"Footer-module_dunsContainer__-mj-b"};
89
+ styleInject(css_248z$8);
90
+
91
+ // src/components/layout/Footer.jsx
92
+ const Footer = ({
93
+ socialSlot,
94
+ legalSlot,
95
+ trustSlot,
96
+ className = ""
97
+ }) => {
98
+ return /*#__PURE__*/jsx("footer", {
99
+ className: `${styles$8.footer} ${className}`.trim(),
100
+ children: /*#__PURE__*/jsxs("div", {
101
+ className: styles$8.footerContent,
102
+ children: [socialSlot && /*#__PURE__*/jsx("div", {
103
+ className: styles$8.topLine,
104
+ children: /*#__PURE__*/jsx("div", {
105
+ className: styles$8.socialIconsContainer,
106
+ children: /*#__PURE__*/jsx("div", {
107
+ className: styles$8.socialIcons,
108
+ children: socialSlot
109
+ })
110
+ })
111
+ }), legalSlot && /*#__PURE__*/jsx("div", {
112
+ className: styles$8.legalLinks,
113
+ children: legalSlot
114
+ }), trustSlot && /*#__PURE__*/jsx("div", {
115
+ className: styles$8.dunsContainer,
116
+ children: trustSlot
117
+ })]
118
+ })
119
+ });
120
+ };
121
+
122
+ var css_248z$7 = ".Button-module_button__uvxtU{align-items:center;background-color:var(--button-bg,var(--btn-primary-bg));border:1px solid var(--button-border,transparent);border-radius:var(--radius-md);color:var(--button-text,var(--btn-primary-text));cursor:pointer;display:inline-flex;flex-shrink:0;font-family:var(--font-sans);font-size:clamp(.8rem,2.5vw,.9rem);font-weight:500;gap:clamp(4px,.5vw,6px);justify-content:center;line-height:1.2;min-height:clamp(32px,8vw,40px);overflow:hidden;padding:clamp(6px,1.2vw,10px) clamp(12px,2.5vw,20px);position:relative;text-decoration:none;transition:background-color .3s ease,color .3s ease,border-color .3s ease,box-shadow .3s ease;user-select:none;white-space:nowrap}.Button-module_button__uvxtU:hover{background-color:var(--button-hover-bg,var(--btn-primary-hover-bg));box-shadow:0 2px 8px var(--shadow-color);color:var(--button-hover-text,var(--btn-primary-hover-text))}.Button-module_button__uvxtU:active{box-shadow:none}.Button-module_button__uvxtU:focus-visible{outline:2px solid var(--focus-border-color);outline-offset:2px}.Button-module_button__uvxtU:disabled{box-shadow:none;cursor:not-allowed;opacity:.55;pointer-events:none}.Button-module_primary__xPba2{--button-bg:var(--btn-primary-bg);--button-text:var(--btn-primary-text);--button-hover-bg:var(--btn-primary-hover-bg);--button-hover-text:var(--btn-primary-hover-text)}.Button-module_secondary__hn72M{--button-bg:var(--btn-secondary-bg);--button-text:var(--btn-secondary-text);--button-hover-bg:var(--btn-secondary-hover-bg);--button-hover-text:var(--btn-secondary-hover-text)}.Button-module_danger__6UD-N{--button-bg:var(--btn-danger-bg);--button-text:var(--btn-danger-text);--button-hover-bg:var(--btn-danger-hover-bg);--button-hover-text:var(--btn-danger-hover-text)}.Button-module_success__B0AQp{--button-bg:var(--btn-success-bg);--button-text:var(--btn-success-text);--button-hover-bg:var(--btn-success-hover-bg);--button-hover-text:var(--btn-success-hover-text)}.Button-module_outline__zE2nr{--button-bg:transparent;--button-hover-bg:var(--hover-color);--button-text:var(--text-color);--button-hover-text:var(--text-color);--button-border:var(--border-color-light)}.Button-module_ghost__Lw5bx{--button-bg:transparent;--button-hover-bg:var(--hover-color);--button-text:var(--text-color);--button-hover-text:var(--text-color);--button-border:transparent;box-shadow:none}.Button-module_ghost__Lw5bx:hover{box-shadow:none}.Button-module_sm__hHCp3{border-radius:var(--radius-sm);font-size:var(--text-xs);min-height:clamp(24px,6vw,32px);padding:clamp(3px,.8vw,5px) clamp(8px,2vw,12px)}.Button-module_lg__8-o98{border-radius:var(--radius-lg);font-size:var(--text-base);min-height:clamp(40px,10vw,56px);padding:clamp(10px,2vw,14px) clamp(20px,5vw,32px)}.Button-module_full__GaUHE{width:100%}.Button-module_icon__bd--q{align-items:center;color:inherit;display:flex;flex-shrink:0}.Button-module_text__NGnws{color:inherit}.Button-module_badge__64QnL{align-items:center;background-color:var(--error-color);border-radius:var(--radius-full);color:var(--btn-primary-text);display:inline-flex;font-size:.65rem;font-weight:700;height:18px;justify-content:center;margin-left:clamp(2px,.5vw,4px);min-width:18px;padding:0 clamp(2px,.5vw,4px)}";
123
+ var styles$7 = {"button":"Button-module_button__uvxtU","primary":"Button-module_primary__xPba2","secondary":"Button-module_secondary__hn72M","danger":"Button-module_danger__6UD-N","success":"Button-module_success__B0AQp","outline":"Button-module_outline__zE2nr","ghost":"Button-module_ghost__Lw5bx","sm":"Button-module_sm__hHCp3","lg":"Button-module_lg__8-o98","full":"Button-module_full__GaUHE","icon":"Button-module_icon__bd--q","text":"Button-module_text__NGnws","badge":"Button-module_badge__64QnL"};
124
+ styleInject(css_248z$7);
125
+
126
+ // src/components/buttons/Button.jsx
127
+ const Button = ({
128
+ children,
129
+ text,
130
+ icon,
131
+ badge,
132
+ badgeClassName,
133
+ intent = "primary",
134
+ appearance = "solid",
135
+ size = "md",
136
+ fullWidth = false,
137
+ href,
138
+ type = "button",
139
+ disabled = false,
140
+ className,
141
+ style,
142
+ onClick,
143
+ ...props
144
+ }) => {
145
+ const label = children ?? text;
146
+ const intentClass = styles$7[intent] ?? styles$7.primary;
147
+ const appearanceClass = appearance === "outline" ? styles$7.outline : appearance === "ghost" ? styles$7.ghost : "";
148
+ const sizeClass = size === "sm" ? styles$7.sm : size === "lg" ? styles$7.lg : "";
149
+ const cls = [styles$7.button, intentClass, appearanceClass, sizeClass, fullWidth ? styles$7.full : "", className ?? ""].filter(Boolean).join(" ");
150
+ const content = /*#__PURE__*/jsxs(Fragment, {
151
+ children: [icon && /*#__PURE__*/jsx("span", {
152
+ className: styles$7.icon,
153
+ "aria-hidden": "true",
154
+ children: icon
155
+ }), label && /*#__PURE__*/jsx("span", {
156
+ className: styles$7.text,
157
+ children: label
158
+ }), badge != null && /*#__PURE__*/jsx("span", {
159
+ className: `${styles$7.badge} ${badgeClassName ?? ""}`.trim(),
160
+ children: badge
161
+ })]
162
+ });
163
+ if (href) {
164
+ return /*#__PURE__*/jsx("a", {
165
+ href: href,
166
+ className: cls,
167
+ style: style,
168
+ ...props,
169
+ children: content
170
+ });
171
+ }
172
+ return /*#__PURE__*/jsx("button", {
173
+ type: type,
174
+ className: cls,
175
+ style: style,
176
+ disabled: disabled,
177
+ onClick: onClick,
178
+ ...props,
179
+ children: content
180
+ });
181
+ };
182
+
183
+ var css_248z$6 = ".FavoriteHeartButton-module_favoriteHeartButton__ml-Uu{align-items:center;background-color:transparent!important;border:none!important;cursor:pointer;display:flex;gap:0!important;height:clamp(32px,8vw,48px)!important;justify-content:center;max-width:clamp(32px,8vw,48px)!important;min-width:clamp(32px,8vw,48px)!important;padding:clamp(4px,1.5vw,8px)!important;transition:opacity .2s ease}.FavoriteHeartButton-module_favorited__01bVq{color:var(--danger-color,#dc3545)!important}.FavoriteHeartButton-module_notFavorited__gU-Ng{color:var(--secondary-text-color)!important}.FavoriteHeartButton-module_favoriteHeartButton__ml-Uu:disabled{cursor:not-allowed;opacity:.6}.FavoriteHeartButton-module_favoriteHeartButton__ml-Uu:hover:not(:disabled){background-color:transparent!important;border:none!important;opacity:.75}";
184
+ var styles$6 = {"favoriteHeartButton":"FavoriteHeartButton-module_favoriteHeartButton__ml-Uu","favorited":"FavoriteHeartButton-module_favorited__01bVq","notFavorited":"FavoriteHeartButton-module_notFavorited__gU-Ng"};
185
+ styleInject(css_248z$6);
186
+
187
+ // src/components/buttons/FavoriteHeartButton.jsx
188
+ const FavoriteHeartButton = ({
189
+ isFavorited,
190
+ onClick,
191
+ disabled,
192
+ isOwner = false,
193
+ className = "",
194
+ style
195
+ }) => {
196
+ if (isOwner) return null;
197
+ return /*#__PURE__*/jsx(Button, {
198
+ onClick: onClick,
199
+ disabled: disabled,
200
+ className: `${styles$6.favoriteHeartButton} ${isFavorited ? styles$6.favorited : styles$6.notFavorited} ${className}`,
201
+ style: style,
202
+ "aria-label": isFavorited ? "Unfavorite" : "Favorite",
203
+ title: isFavorited ? "Unfavorite" : "Favorite",
204
+ icon: /*#__PURE__*/jsx(HeartIcon, {
205
+ style: {
206
+ width: 20,
207
+ height: 20
208
+ }
209
+ })
210
+ });
211
+ };
212
+
213
+ // src/components/buttons/ScrollButton.jsx
214
+ const ScrollButton = ({
215
+ direction = "up",
216
+ onClick,
217
+ className = "",
218
+ style = {}
219
+ }) => {
220
+ const icon = direction === "up" ? /*#__PURE__*/jsx(FaArrowUp, {}) : /*#__PURE__*/jsx(FaArrowDown, {});
221
+ const label = direction === "up" ? "Scroll to top" : "Scroll to bottom";
222
+ return /*#__PURE__*/jsx(Button, {
223
+ icon: icon,
224
+ onClick: onClick,
225
+ className: className,
226
+ appearance: "ghost",
227
+ "aria-label": label,
228
+ title: label,
229
+ style: {
230
+ display: "flex",
231
+ ...style
232
+ }
233
+ });
234
+ };
235
+
236
+ var css_248z$5 = ".ThreeDotButton-module_threeDotButton__yBrhU{gap:0!important;height:44px!important;max-width:44px!important;min-width:44px!important;padding:6px!important;width:44px!important}.ThreeDotButton-module_threeDotButton__yBrhU,.ThreeDotButton-module_threeDotButton__yBrhU:active,.ThreeDotButton-module_threeDotButton__yBrhU:hover{background:transparent!important;background-color:transparent!important;border:none!important}.ThreeDotButton-module_threeDotButton__yBrhU:focus-visible{border-radius:var(--radius-sm,4px);outline:2px solid var(--accent-color,#007bff)}.ThreeDotButton-module_dotsWrapper__mDkka{align-items:center;display:inline-flex;flex-direction:column;gap:3px;justify-content:center}.ThreeDotButton-module_dot__pzOIM{background:currentColor;border-radius:50%;display:inline-block;height:4px;width:4px}";
237
+ var styles$5 = {"threeDotButton":"ThreeDotButton-module_threeDotButton__yBrhU","dotsWrapper":"ThreeDotButton-module_dotsWrapper__mDkka","dot":"ThreeDotButton-module_dot__pzOIM"};
238
+ styleInject(css_248z$5);
239
+
240
+ // src/components/buttons/ThreeDotButton.jsx
241
+ const ThreeDotButton = ({
242
+ className = "",
243
+ ariaLabel = "More options",
244
+ onClick
245
+ }) => {
246
+ return /*#__PURE__*/jsx(Button, {
247
+ className: `${styles$5.threeDotButton} ${className}`,
248
+ onClick: onClick,
249
+ "aria-label": ariaLabel,
250
+ title: ariaLabel,
251
+ icon: /*#__PURE__*/jsxs("span", {
252
+ className: styles$5.dotsWrapper,
253
+ "aria-hidden": "true",
254
+ children: [/*#__PURE__*/jsx("span", {
255
+ className: styles$5.dot
256
+ }), /*#__PURE__*/jsx("span", {
257
+ className: styles$5.dot
258
+ }), /*#__PURE__*/jsx("span", {
259
+ className: styles$5.dot
260
+ })]
261
+ })
262
+ });
263
+ };
264
+
265
+ var css_248z$4 = ".Container-module_container__d-oB8{margin-left:auto;margin-right:auto;max-width:var(--container-max-width,1280px);padding-left:var(--section-padding-x);padding-right:var(--section-padding-x);width:100%}.Container-module_narrow__mC8nM{max-width:768px}.Container-module_wide__kBARu{max-width:1536px}.Container-module_full__fv2YK{max-width:none}";
266
+ var styles$4 = {"container":"Container-module_container__d-oB8","narrow":"Container-module_narrow__mC8nM","wide":"Container-module_wide__kBARu","full":"Container-module_full__fv2YK"};
267
+ styleInject(css_248z$4);
268
+
269
+ // src/components/common/Container.jsx
270
+ const Container = ({
271
+ children,
272
+ size = "default",
273
+ className,
274
+ style,
275
+ as: Tag = "div",
276
+ ...props
277
+ }) => {
278
+ const sizeClass = size === "narrow" ? styles$4.narrow : size === "wide" ? styles$4.wide : size === "full" ? styles$4.full : "";
279
+ const cls = [styles$4.container, sizeClass, className ?? ""].filter(Boolean).join(" ");
280
+ return /*#__PURE__*/jsx(Tag, {
281
+ className: cls,
282
+ style: style,
283
+ ...props,
284
+ children: children
285
+ });
286
+ };
287
+
288
+ var css_248z$3 = ".Section-module_section__fir88{background-color:var(--bg-color);padding-bottom:var(--section-padding-y);padding-top:var(--section-padding-y);width:100%}.Section-module_alternate__Y1rWg{background-color:var(--section-bg)}.Section-module_card__p-Uae{background-color:var(--card-bg);border:1px solid var(--border-color-light);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}.Section-module_tight__MBRrm{padding-bottom:calc(var(--section-padding-y)*.5);padding-top:calc(var(--section-padding-y)*.5)}.Section-module_flush__kPYbL{padding-bottom:0;padding-top:0}.Section-module_header__4Xl-D{margin-bottom:var(--space-8);text-align:center}.Section-module_title__XCRy8{color:var(--heading-color);font-size:clamp(var(--text-xl),4vw,var(--text-3xl));font-weight:700;line-height:1.2;margin-bottom:var(--space-3)}.Section-module_subtitle__qJc4y{color:var(--secondary-text-color);font-size:clamp(var(--text-sm),2vw,var(--text-base));margin-left:auto;margin-right:auto;max-width:640px}";
289
+ var styles$3 = {"section":"Section-module_section__fir88","alternate":"Section-module_alternate__Y1rWg","card":"Section-module_card__p-Uae","tight":"Section-module_tight__MBRrm","flush":"Section-module_flush__kPYbL","header":"Section-module_header__4Xl-D","title":"Section-module_title__XCRy8","subtitle":"Section-module_subtitle__qJc4y"};
290
+ styleInject(css_248z$3);
291
+
292
+ // src/components/common/Section.jsx
293
+ const Section = ({
294
+ children,
295
+ variant = "default",
296
+ padding = "default",
297
+ title,
298
+ subtitle,
299
+ containerSize = "default",
300
+ className,
301
+ style,
302
+ as: Tag = "section",
303
+ ...props
304
+ }) => {
305
+ const variantClass = variant === "alternate" ? styles$3.alternate : variant === "card" ? styles$3.card : "";
306
+ const paddingClass = padding === "tight" ? styles$3.tight : padding === "flush" ? styles$3.flush : "";
307
+ const cls = [styles$3.section, variantClass, paddingClass, className ?? ""].filter(Boolean).join(" ");
308
+ return /*#__PURE__*/jsx(Tag, {
309
+ className: cls,
310
+ style: style,
311
+ ...props,
312
+ children: /*#__PURE__*/jsxs(Container, {
313
+ size: containerSize,
314
+ children: [(title || subtitle) && /*#__PURE__*/jsxs("div", {
315
+ className: styles$3.header,
316
+ children: [title && /*#__PURE__*/jsx("h2", {
317
+ className: styles$3.title,
318
+ children: title
319
+ }), subtitle && /*#__PURE__*/jsx("p", {
320
+ className: styles$3.subtitle,
321
+ children: subtitle
322
+ })]
323
+ }), children]
324
+ })
325
+ });
326
+ };
327
+
328
+ var css_248z$2 = ".Modal-module_modalOverlay__ZH3r4{align-items:center;animation:Modal-module_fadeIn__qc5Zc .25s ease;background-color:rgba(0,0,0,.7);bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:10000}.Modal-module_modalContent__qNq5W{animation:Modal-module_slideIn__1Jc8w .25s ease;background-color:var(--card-bg);border:1px solid var(--border-color-light);border-radius:var(--radius-md,8px);box-shadow:0 4px 20px var(--shadow-color,rgba(0,0,0,.2));max-height:90vh;overflow-y:auto;padding:clamp(16px,4vw,24px);position:relative;transition:background-color .3s ease;width:clamp(300px,90vw,480px)}@keyframes Modal-module_fadeIn__qc5Zc{0%{opacity:0}to{opacity:1}}@keyframes Modal-module_slideIn__1Jc8w{0%{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:translateY(0)}}";
329
+ var styles$2 = {"modalOverlay":"Modal-module_modalOverlay__ZH3r4","modalContent":"Modal-module_modalContent__qNq5W"};
330
+ styleInject(css_248z$2);
331
+
332
+ const emptySubscribe = () => () => {};
333
+ const useIsMounted = () => useSyncExternalStore(emptySubscribe, () => true, () => false);
334
+ const Modal = ({
335
+ isOpen,
336
+ onClose,
337
+ children,
338
+ className
339
+ }) => {
340
+ const mounted = useIsMounted();
341
+
342
+ // Lock body scroll when modal is open
343
+ useEffect(() => {
344
+ if (isOpen) {
345
+ document.body.style.overflow = "hidden";
346
+ document.body.style.position = "fixed";
347
+ document.body.style.width = "100%";
348
+ } else {
349
+ document.body.style.overflow = "";
350
+ document.body.style.position = "";
351
+ document.body.style.width = "";
352
+ }
353
+ return () => {
354
+ document.body.style.overflow = "";
355
+ document.body.style.position = "";
356
+ document.body.style.width = "";
357
+ };
358
+ }, [isOpen]);
359
+
360
+ // ESC key closes modal
361
+ useEffect(() => {
362
+ const handleEsc = e => {
363
+ if (e.key === "Escape" && isOpen) onClose();
364
+ };
365
+ if (isOpen) document.addEventListener("keydown", handleEsc);
366
+ return () => document.removeEventListener("keydown", handleEsc);
367
+ }, [isOpen, onClose]);
368
+ if (!isOpen || !mounted) return null;
369
+ const handleBackdropClick = e => {
370
+ if (e.target === e.currentTarget) onClose();
371
+ };
372
+ return /*#__PURE__*/createPortal(/*#__PURE__*/jsx("div", {
373
+ className: styles$2.modalOverlay,
374
+ onClick: handleBackdropClick,
375
+ role: "dialog",
376
+ "aria-modal": "true",
377
+ children: /*#__PURE__*/jsx("div", {
378
+ className: `${styles$2.modalContent} ${className ?? ""}`,
379
+ children: children
380
+ })
381
+ }), document.body);
382
+ };
383
+
384
+ var css_248z$1 = ".ProgressBar-module_wrapper__Sbkwa{display:flex;flex-direction:column;gap:4px;width:100%}.ProgressBar-module_track__-FjJA{background-color:var(--progress-bg,rgba(0,0,0,.1));border-radius:var(--radius-full,9999px);overflow:hidden;width:100%}.ProgressBar-module_bar__zrEy7{background:var(--primary-color,#007bff);border-radius:var(--radius-full,9999px);height:100%;transition:width 0ms}.ProgressBar-module_label__RpKiv{color:var(--secondary-text-color);font-size:var(--text-xs,11px);text-align:right}";
385
+ var styles$1 = {"wrapper":"ProgressBar-module_wrapper__Sbkwa","track":"ProgressBar-module_track__-FjJA","bar":"ProgressBar-module_bar__zrEy7","label":"ProgressBar-module_label__RpKiv"};
386
+ styleInject(css_248z$1);
387
+
388
+ const ProgressBar = ({
389
+ progress = 0,
390
+ height = 6,
391
+ color = "var(--primary-color, #007bff)",
392
+ backgroundColor = "var(--progress-bg, rgba(0, 0, 0, 0.1))",
393
+ animate = true,
394
+ speed = 300,
395
+ showLabel = false,
396
+ labelPosition = "top",
397
+ onComplete = null,
398
+ className = "",
399
+ style = {}
400
+ }) => {
401
+ const [animatedProgress, setAnimatedProgress] = useState(0);
402
+ const rafIdRef = useRef(null);
403
+ const startRef = useRef(0);
404
+ const endRef = useRef(progress);
405
+ const startTimeRef = useRef(null);
406
+ const completedRef = useRef(false);
407
+ const easeOutCubic = t => 1 - Math.pow(1 - t, 3);
408
+ useEffect(() => {
409
+ if (!animate) return;
410
+ startRef.current = animatedProgress;
411
+ }, [animatedProgress, animate]);
412
+ useEffect(() => {
413
+ if (!animate) return; // non-animated: use progress directly via clampedProgress below
414
+ if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current);
415
+ endRef.current = progress;
416
+ startTimeRef.current = null;
417
+ if (startRef.current === endRef.current) return;
418
+ const delta = Math.abs(endRef.current - startRef.current);
419
+ const duration = Math.max(speed, Math.min(1500, 20 * delta));
420
+ const step = ts => {
421
+ if (startTimeRef.current === null) startTimeRef.current = ts;
422
+ const elapsed = ts - startTimeRef.current;
423
+ const t = Math.max(0, Math.min(1, elapsed / duration));
424
+ const eased = easeOutCubic(t);
425
+ const next = startRef.current + (endRef.current - startRef.current) * eased;
426
+ setAnimatedProgress(next);
427
+ if (t < 1) {
428
+ rafIdRef.current = requestAnimationFrame(step);
429
+ } else {
430
+ setAnimatedProgress(endRef.current);
431
+ if (endRef.current >= 100 && onComplete && !completedRef.current) {
432
+ completedRef.current = true;
433
+ onComplete();
434
+ }
435
+ }
436
+ };
437
+ rafIdRef.current = requestAnimationFrame(step);
438
+ return () => {
439
+ if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current);
440
+ };
441
+ }, [progress, animate, speed, onComplete]);
442
+
443
+ // When not animated, use progress directly; when animated, use animatedProgress
444
+ const clampedProgress = Math.max(0, Math.min(100, animate ? animatedProgress : progress));
445
+ const label = `${Math.round(clampedProgress)}%`;
446
+ return /*#__PURE__*/jsxs("div", {
447
+ className: `${styles$1.wrapper} ${className}`,
448
+ style: style,
449
+ role: "progressbar",
450
+ "aria-valuenow": Math.round(clampedProgress),
451
+ "aria-valuemin": 0,
452
+ "aria-valuemax": 100,
453
+ children: [showLabel && labelPosition === "top" && /*#__PURE__*/jsx("span", {
454
+ className: styles$1.label,
455
+ children: label
456
+ }), /*#__PURE__*/jsx("div", {
457
+ className: styles$1.track,
458
+ style: {
459
+ height,
460
+ backgroundColor
461
+ },
462
+ children: /*#__PURE__*/jsx("div", {
463
+ className: styles$1.bar,
464
+ style: {
465
+ width: `${clampedProgress}%`,
466
+ background: color
467
+ }
468
+ })
469
+ }), showLabel && labelPosition === "bottom" && /*#__PURE__*/jsx("span", {
470
+ className: styles$1.label,
471
+ children: label
472
+ })]
473
+ });
474
+ };
475
+
476
+ const ThemeContext = /*#__PURE__*/createContext();
477
+ const ThemeProvider = ({
478
+ children
479
+ }) => {
480
+ const [mounted, setMounted] = useState(false);
481
+ const [theme, setTheme] = useState("light"); // SSR fallback
482
+
483
+ // Step 1: On mount, load theme from localStorage. Default = dark.
484
+ // Defer state updates so this effect is not classified as synchronous setState-in-effect (react-hooks/set-state-in-effect).
485
+ useEffect(() => {
486
+ let cancelled = false;
487
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
488
+ const onSystemChange = e => {
489
+ if (!localStorage.getItem("theme")) {
490
+ const sys = e.matches ? "dark" : "light";
491
+ setTheme(sys);
492
+ }
493
+ };
494
+ queueMicrotask(() => {
495
+ if (cancelled) return;
496
+ try {
497
+ const saved = localStorage.getItem("theme");
498
+ const resolved = saved ?? "dark"; // First visit = dark
499
+ setTheme(resolved);
500
+ document.documentElement.setAttribute("data-theme", resolved);
501
+ mq.addEventListener("change", onSystemChange);
502
+ setMounted(true);
503
+ } catch {
504
+ if (cancelled) return;
505
+ setTheme("dark");
506
+ document.documentElement.setAttribute("data-theme", "dark");
507
+ setMounted(true);
508
+ }
509
+ });
510
+ return () => {
511
+ cancelled = true;
512
+ mq.removeEventListener("change", onSystemChange);
513
+ };
514
+ }, []);
515
+
516
+ // Step 2: Apply theme with smooth transition class
517
+ const applyTheme = useCallback(next => {
518
+ const root = document.documentElement;
519
+ root.classList.add("theme-transition");
520
+ root.setAttribute("data-theme", next);
521
+ localStorage.setItem("theme", next);
522
+ const t = setTimeout(() => root.classList.remove("theme-transition"), 300);
523
+ return () => clearTimeout(t);
524
+ }, []);
525
+
526
+ // Step 3: Apply whenever theme state changes (after mount)
527
+ useEffect(() => {
528
+ if (mounted) applyTheme(theme);
529
+ }, [theme, mounted, applyTheme]);
530
+
531
+ // Step 4: Toggle
532
+ const toggleTheme = useCallback(() => {
533
+ setTheme(prev => prev === "light" ? "dark" : "light");
534
+ }, []);
535
+
536
+ // Step 5: Explicit setter (for admin/testing)
537
+ const setThemeExplicitly = useCallback(next => {
538
+ if (next !== "light" && next !== "dark") return;
539
+ setTheme(next);
540
+ }, []);
541
+
542
+ // React 19 direct context syntax
543
+ return /*#__PURE__*/jsx(ThemeContext, {
544
+ value: {
545
+ theme,
546
+ toggleTheme,
547
+ setTheme: setThemeExplicitly,
548
+ isDarkMode: theme === "dark",
549
+ isThemeReady: mounted
550
+ },
551
+ children: children
552
+ });
553
+ };
554
+ const useTheme = () => {
555
+ const ctx = useContext(ThemeContext);
556
+ if (!ctx) throw new Error("useTheme must be used inside ThemeProvider");
557
+ return ctx;
558
+ };
559
+
560
+ var css_248z = ".Layout-module_wrapper__NiDzy{display:flex;flex-direction:column;min-height:100vh}.Layout-module_content__JaQFC{flex:1 0 auto;margin-top:clamp(48px,10vw,64px)}.Layout-module_main__cP0Rc{width:100%}.Layout-module_footerWrapper__oYfqA{flex-shrink:0}";
561
+ var styles = {"wrapper":"Layout-module_wrapper__NiDzy","content":"Layout-module_content__JaQFC","main":"Layout-module_main__cP0Rc","footerWrapper":"Layout-module_footerWrapper__oYfqA"};
562
+ styleInject(css_248z);
563
+
564
+ // src/layouts/Layout.jsx
565
+ const Layout = ({
566
+ children
567
+ }) => {
568
+ return /*#__PURE__*/jsxs("div", {
569
+ className: styles.wrapper,
570
+ children: [/*#__PURE__*/jsx(Navbar, {}), /*#__PURE__*/jsx("div", {
571
+ className: styles.content,
572
+ children: /*#__PURE__*/jsx("main", {
573
+ className: styles.main,
574
+ children: children
575
+ })
576
+ }), /*#__PURE__*/jsx("div", {
577
+ className: styles.footerWrapper,
578
+ children: /*#__PURE__*/jsx(Footer, {})
579
+ })]
580
+ });
581
+ };
582
+
583
+ export { Button, Container, FaArrowDown, FaArrowUp, FavoriteHeartButton, Footer, HeartIcon, Layout, Modal, Navbar, ProgressBar, ScrollButton, Section, SubNavbar, ThemeProvider, ThreeDotButton, useTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanvika/ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Sanvika Production — shared UI component library for 50+ projects (pure JS, CSS Modules, props-driven) + cloud-driven Navbar/Theme presets via ui.sanvikaproduction.com",
@@ -15,29 +15,38 @@ export const ThemeProvider = ({ children }) => {
15
15
  const [theme, setTheme] = useState("light"); // SSR fallback
16
16
 
17
17
  // Step 1: On mount, load theme from localStorage. Default = dark.
18
+ // Defer state updates so this effect is not classified as synchronous setState-in-effect (react-hooks/set-state-in-effect).
18
19
  useEffect(() => {
19
- try {
20
- const saved = localStorage.getItem("theme");
21
- const resolved = saved ?? "dark"; // First visit = dark
22
- setTheme(resolved);
23
- document.documentElement.setAttribute("data-theme", resolved);
20
+ let cancelled = false;
21
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
22
+ const onSystemChange = (e) => {
23
+ if (!localStorage.getItem("theme")) {
24
+ const sys = e.matches ? "dark" : "light";
25
+ setTheme(sys);
26
+ }
27
+ };
24
28
 
25
- // Listen for OS-level theme changes only if user has not set a preference
26
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
27
- const onSystemChange = (e) => {
28
- if (!localStorage.getItem("theme")) {
29
- const sys = e.matches ? "dark" : "light";
30
- setTheme(sys);
31
- }
32
- };
33
- mq.addEventListener("change", onSystemChange);
34
- setMounted(true);
35
- return () => mq.removeEventListener("change", onSystemChange);
36
- } catch {
37
- setTheme("dark");
38
- document.documentElement.setAttribute("data-theme", "dark");
39
- setMounted(true);
40
- }
29
+ queueMicrotask(() => {
30
+ if (cancelled) return;
31
+ try {
32
+ const saved = localStorage.getItem("theme");
33
+ const resolved = saved ?? "dark"; // First visit = dark
34
+ setTheme(resolved);
35
+ document.documentElement.setAttribute("data-theme", resolved);
36
+ mq.addEventListener("change", onSystemChange);
37
+ setMounted(true);
38
+ } catch {
39
+ if (cancelled) return;
40
+ setTheme("dark");
41
+ document.documentElement.setAttribute("data-theme", "dark");
42
+ setMounted(true);
43
+ }
44
+ });
45
+
46
+ return () => {
47
+ cancelled = true;
48
+ mq.removeEventListener("change", onSystemChange);
49
+ };
41
50
  }, []);
42
51
 
43
52
  // Step 2: Apply theme with smooth transition class