funuicss 3.9.13 → 3.9.14

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.9.13",
2
+ "version": "3.9.14",
3
3
  "name": "funuicss",
4
4
  "description": "React and Next.js component UI Library for creating Easy and good looking websites with fewer lines of code. Elevate your web development experience with our cutting-edge React/Next.js component UI Library. Craft stunning websites effortlessly, boasting both seamless functionality and aesthetic appeal—all achieved with minimal lines of code. Unleash the power of simplicity and style in your projects!",
5
5
  "main": "index.js",
@@ -31,6 +31,7 @@ interface NavbarProps {
31
31
  rightLinks?: NavLink[] | string;
32
32
  renderLink?: (link: NavLink, index: number) => React.ReactNode;
33
33
  mobileMenuBreakpoint?: number;
34
+ visibleLinks?: boolean;
34
35
  logoType?: 'text' | 'image' | 'both' | 'none';
35
36
  logoText?: string;
36
37
  logoTextSize?: string;
@@ -85,9 +85,11 @@ var DropdownArrow = function (_a) {
85
85
  };
86
86
  // Link Item Component with Dropdown Support
87
87
  var LinkItem = function (_a) {
88
- var link = _a.link, renderLink = _a.renderLink, _b = _a.linkPadding, linkPadding = _b === void 0 ? '' : _b, _c = _a.activeLinkColor, activeLinkColor = _c === void 0 ? 'primary' : _c, _d = _a.dropdownArrow, dropdownArrow = _d === void 0 ? true : _d, _e = _a.isMobile, isMobile = _e === void 0 ? false : _e;
89
- var _f = (0, react_1.useState)(false), isOpen = _f[0], setIsOpen = _f[1];
90
- var _g = (0, react_1.useState)(null), iconNode = _g[0], setIconNode = _g[1];
88
+ var link = _a.link, renderLink = _a.renderLink, _b = _a.linkPadding, linkPadding = _b === void 0 ? '' : _b, _c = _a.activeLinkColor, activeLinkColor = _c === void 0 ? 'primary' : _c, _d = _a.dropdownArrow, dropdownArrow = _d === void 0 ? true : _d, _e = _a.isMobile, isMobile = _e === void 0 ? false : _e, _f = _a.visibleLinks // Add visibleLinks prop here
89
+ , visibleLinks = _f === void 0 ? false : _f // Add visibleLinks prop here
90
+ ;
91
+ var _g = (0, react_1.useState)(false), isOpen = _g[0], setIsOpen = _g[1];
92
+ var _h = (0, react_1.useState)(null), iconNode = _h[0], setIconNode = _h[1];
91
93
  var timeoutRef = (0, react_1.useRef)();
92
94
  var dropdownRef = (0, react_1.useRef)(null);
93
95
  // Handle dynamic icon loading
@@ -117,17 +119,17 @@ var LinkItem = function (_a) {
117
119
  var handleMouseEnter = function () {
118
120
  if (timeoutRef.current)
119
121
  clearTimeout(timeoutRef.current);
120
- if (!isMobile && hasChildren) {
122
+ if ((!isMobile || visibleLinks) && hasChildren) { // Updated condition
121
123
  setIsOpen(true);
122
124
  }
123
125
  };
124
126
  var handleMouseLeave = function () {
125
- if (!isMobile) {
127
+ if (!isMobile || visibleLinks) { // Updated condition
126
128
  timeoutRef.current = setTimeout(function () { return setIsOpen(false); }, 150);
127
129
  }
128
130
  };
129
131
  var handleClick = function (e) {
130
- if (hasChildren && isMobile) {
132
+ if (hasChildren && (isMobile && !visibleLinks)) { // Only toggle on mobile when visibleLinks is false
131
133
  e.preventDefault();
132
134
  setIsOpen(!isOpen);
133
135
  }
@@ -156,11 +158,15 @@ var LinkItem = function (_a) {
156
158
  display: 'flex',
157
159
  alignItems: 'center'
158
160
  } }, linkContent),
159
- hasChildren && isOpen && (React.createElement("div", { className: "nav_dropdown-menu ".concat(isMobile ? 'nav_dropdown-mobile' : '') }, link.children.map(function (child, index) { return (React.createElement(LinkItem, { key: index, link: child, renderLink: renderLink, linkPadding: linkPadding, activeLinkColor: activeLinkColor, dropdownArrow: dropdownArrow, isMobile: isMobile })); })))));
161
+ hasChildren && isOpen && (React.createElement("div", { className: "nav_dropdown-menu ".concat((isMobile && !visibleLinks) ? 'nav_dropdown-mobile' : '') },
162
+ " ",
163
+ link.children.map(function (child, index) { return (React.createElement(LinkItem, { key: index, link: child, renderLink: renderLink, linkPadding: linkPadding, activeLinkColor: activeLinkColor, dropdownArrow: dropdownArrow, isMobile: isMobile, visibleLinks: visibleLinks })); })))));
160
164
  };
161
165
  // Links component to render navigation links
162
166
  var NavLinks = function (_a) {
163
- var links = _a.links, renderLink = _a.renderLink, _b = _a.linkGap, linkGap = _b === void 0 ? '1rem' : _b, _c = _a.linkPadding, linkPadding = _c === void 0 ? '0.5rem 1rem' : _c, _d = _a.activeLinkColor, activeLinkColor = _d === void 0 ? 'primary' : _d, _e = _a.dropdownArrow, dropdownArrow = _e === void 0 ? true : _e, _f = _a.isMobile, isMobile = _f === void 0 ? false : _f;
167
+ var links = _a.links, renderLink = _a.renderLink, _b = _a.linkGap, linkGap = _b === void 0 ? '1rem' : _b, _c = _a.linkPadding, linkPadding = _c === void 0 ? '0.5rem 1rem' : _c, _d = _a.activeLinkColor, activeLinkColor = _d === void 0 ? 'primary' : _d, _e = _a.dropdownArrow, dropdownArrow = _e === void 0 ? true : _e, _f = _a.isMobile, isMobile = _f === void 0 ? false : _f, _g = _a.visibleLinks // Add visibleLinks prop here
168
+ , visibleLinks = _g === void 0 ? false : _g // Add visibleLinks prop here
169
+ ;
164
170
  if (!links || !Array.isArray(links) || links.length === 0) {
165
171
  return null;
166
172
  }
@@ -168,8 +174,8 @@ var NavLinks = function (_a) {
168
174
  display: 'flex',
169
175
  alignItems: 'center',
170
176
  gap: linkGap,
171
- flexDirection: isMobile ? 'column' : 'row'
172
- } }, links.map(function (link, index) { return (React.createElement(LinkItem, { key: index, link: link, renderLink: renderLink, linkPadding: linkPadding, activeLinkColor: activeLinkColor, dropdownArrow: dropdownArrow, isMobile: isMobile })); })));
177
+ flexDirection: (isMobile && !visibleLinks) ? 'column' : 'row' // Only column layout when mobile menu is open
178
+ } }, links.map(function (link, index) { return (React.createElement(LinkItem, { key: index, link: link, renderLink: renderLink, linkPadding: linkPadding, activeLinkColor: activeLinkColor, dropdownArrow: dropdownArrow, isMobile: isMobile, visibleLinks: visibleLinks })); })));
173
179
  };
174
180
  // Logo component with multiple display options
175
181
  var Logo = function (_a) {
@@ -244,46 +250,590 @@ function AppBar(localProps) {
244
250
  var hasLeftLinks = parsedLeftLinks.length > 0;
245
251
  return (React.createElement("div", { className: "left-section", style: { display: 'flex', alignItems: 'center', gap: '2rem' } },
246
252
  shouldRenderLogo && (React.createElement(Logo, { type: final.logoType, text: final.logoText, textSize: final.logoTextSize, textColor: final.logoTextColor, textWeight: final.logoTextWeight, url: final.logoUrl, alt: final.logoAlt, width: final.logoWidth, height: final.logoHeight, href: final.logoHref, onClick: final.onLogoClick })),
247
- hasLeftLinks && !isMobileScreen && (React.createElement(NavLinks, { links: parsedLeftLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow }))));
253
+ hasLeftLinks && (!isMobileScreen || final.visibleLinks) && ( // Updated condition
254
+ React.createElement(NavLinks, { links: parsedLeftLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow, isMobile: isMobileScreen, visibleLinks: final.visibleLinks }))));
248
255
  };
249
256
  var renderCenterSection = function () {
250
257
  if (final.center)
251
258
  return final.center;
252
- if (parsedCenterLinks.length > 0 && !isMobileScreen) {
253
- return (React.createElement(NavLinks, { links: parsedCenterLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow }));
259
+ if (parsedCenterLinks.length > 0 && (!isMobileScreen || final.visibleLinks)) { // Updated condition
260
+ return (React.createElement(NavLinks, { links: parsedCenterLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow, isMobile: isMobileScreen, visibleLinks: final.visibleLinks }));
254
261
  }
255
262
  return null;
256
263
  };
257
264
  var renderRightSection = function () {
258
265
  if (final.right)
259
266
  return final.right;
260
- if (parsedRightLinks.length > 0 && !isMobileScreen) {
261
- return (React.createElement(NavLinks, { links: parsedRightLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow }));
267
+ if (parsedRightLinks.length > 0 && (!isMobileScreen || final.visibleLinks)) { // Updated condition
268
+ return (React.createElement(NavLinks, { links: parsedRightLinks, renderLink: final.renderLink, linkGap: final.linkGap, linkPadding: final.linkPadding, activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow, isMobile: isMobileScreen, visibleLinks: final.visibleLinks }));
262
269
  }
263
270
  return null;
264
271
  };
265
- // Mobile menu content
272
+ // Mobile menu content - only show when visibleLinks is false
266
273
  var renderMobileMenu = function () {
267
- if (!isMobileScreen || !isMobileMenuOpen)
268
- return null;
274
+ if (!isMobileScreen || !isMobileMenuOpen || final.visibleLinks)
275
+ return null; // Don't show mobile menu when visibleLinks is true
269
276
  var allLinks = __spreadArray(__spreadArray(__spreadArray([], parsedLeftLinks, true), parsedCenterLinks, true), parsedRightLinks, true);
270
277
  return (React.createElement("div", { className: "nav_mobile-menu" },
271
- React.createElement(NavLinks, { links: allLinks, renderLink: final.renderLink, linkGap: "0.5rem", linkPadding: "1rem", activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow, isMobile: true })));
278
+ React.createElement(NavLinks, { links: allLinks, renderLink: final.renderLink, linkGap: "0.5rem", linkPadding: "1rem", activeLinkColor: final.activeLinkColor, dropdownArrow: final.dropdownArrow, isMobile: true, visibleLinks: final.visibleLinks })));
272
279
  };
273
280
  return (React.createElement(React.Fragment, null,
274
- React.createElement("nav", { id: 'appBar', className: "navigation-bar\n ".concat(isMobileMenuOpen ? 'navbar-mobile-open' : '', "\n ").concat(final.funcss || '', "\n ").concat(final.testing ? "" : final.fixedTop ? 'fixed_top_navbar' : '', "\n ").concat(final.sideBar ? 'there_is_sidebar' : '', "\n ").concat(final.transparent ? 'transparent' : '', "\n ").concat(final.fixedBottom ? 'fixedBottom' : '', "\n "), style: {
281
+ React.createElement("nav", { id: 'appBar', className: "navigation-bar\n ".concat(isMobileMenuOpen ? 'navbar-mobile-open' : '', "\n ").concat(final.funcss || '', "\n ").concat(final.testing ? "" : final.fixedTop ? 'fixed_top_navbar' : '', "\n ").concat(final.sideBar ? 'there_is_sidebar' : '', "\n ").concat(final.transparent ? 'transparent' : '', "\n ").concat(final.fixedBottom ? 'fixedBottom' : '', "\n ").concat(final.visibleLinks ? 'visible-links-mode' : '', " // Add class for styling\n "), style: {
275
282
  padding: "".concat(final.padding || ''),
276
283
  justifyContent: "".concat(final.justify || ''),
277
284
  } },
278
285
  React.createElement("div", { className: "logoWrapper" },
279
286
  renderLeftSection(),
280
- isMobileScreen && isMobileMenuOpen && (React.createElement("div", { className: "hover-text-error pointer _closeNav", onClick: closeMenu },
287
+ isMobileScreen && isMobileMenuOpen && !final.visibleLinks && ( // Only show close button when not in visibleLinks mode
288
+ React.createElement("div", { className: "hover-text-error pointer _closeNav", onClick: closeMenu },
281
289
  React.createElement(Trigger, { isOpen: isMobileMenuOpen })))),
282
290
  React.createElement("div", { className: "linkWrapper" }, renderCenterSection()),
283
291
  React.createElement("div", { className: "linkWrapper" }, renderRightSection()),
284
- isMobileScreen && !isMobileMenuOpen && (React.createElement(React.Fragment, null, final.hasSidebar ?
292
+ isMobileScreen && !isMobileMenuOpen && !final.visibleLinks && (React.createElement(React.Fragment, null, final.hasSidebar ?
285
293
  React.createElement("span", { className: "sidebar-trigger pointer hover-text-primary", onClick: final.openSidebar }, final.sidebarTrigger || React.createElement(Trigger, { isOpen: final.sidebarOpen }))
286
294
  :
287
295
  React.createElement("span", { className: "sidebar-trigger pointer hover-text-primary", onClick: toggleMenu }, final.sidebarTrigger || React.createElement(Trigger, { isOpen: isMobileMenuOpen }))))),
288
296
  renderMobileMenu()));
289
297
  }
298
+ // 'use client';
299
+ // import * as React from 'react';
300
+ // import { useState, useEffect, useRef } from 'react';
301
+ // import { usePathname } from 'next/navigation';
302
+ // import Hamburger from './Hamburger';
303
+ // import { useComponentConfiguration } from '../../utils/componentUtils';
304
+ // import { getDynamicIcon } from '../../utils/getDynamicIcon';
305
+ // interface NavLink {
306
+ // label: string;
307
+ // href: string;
308
+ // icon?: string;
309
+ // iconPosition?: 'prefix' | 'suffix';
310
+ // children?: NavLink[];
311
+ // active?: boolean;
312
+ // className?: string;
313
+ // }
314
+ // interface NavbarProps {
315
+ // // Layout & Behavior
316
+ // fixedTop?: boolean;
317
+ // funcss?: string;
318
+ // padding?: string;
319
+ // fixedBottom?: boolean;
320
+ // justify?: string;
321
+ // transparent?: boolean;
322
+ // testing?: boolean;
323
+ // // Content Sections
324
+ // children?: React.ReactNode;
325
+ // left?: React.ReactNode;
326
+ // center?: React.ReactNode;
327
+ // right?: React.ReactNode;
328
+ // // Sidebar
329
+ // sidebarTrigger?: React.ReactNode;
330
+ // sideBar?: number;
331
+ // hasSidebar?: boolean;
332
+ // sidebarOpen?: boolean;
333
+ // openSidebar?: () => void;
334
+ // // Variant Support
335
+ // variant?: string;
336
+ // // Navigation Links
337
+ // leftLinks?: NavLink[] | string;
338
+ // centerLinks?: NavLink[] | string;
339
+ // rightLinks?: NavLink[] | string;
340
+ // renderLink?: (link: NavLink, index: number) => React.ReactNode;
341
+ // mobileMenuBreakpoint?: number;
342
+ // // Logo Customization
343
+ // logoType?: 'text' | 'image' | 'both' | 'none';
344
+ // logoText?: string;
345
+ // logoTextSize?: string;
346
+ // logoTextColor?: string;
347
+ // logoTextWeight?: string;
348
+ // logoUrl?: string;
349
+ // logoAlt?: string;
350
+ // logoWidth?: string;
351
+ // logoHeight?: string;
352
+ // logoHref?: string;
353
+ // onLogoClick?: () => void;
354
+ // // Link Styling
355
+ // linkGap?: string;
356
+ // linkPadding?: string;
357
+ // activeLinkColor?: string;
358
+ // dropdownArrow?: boolean;
359
+ // }
360
+ // // Parse string to object utility
361
+ // const parseIfString = <T,>(value: T | string, fallback: T): T => {
362
+ // if (typeof value === 'string') {
363
+ // try {
364
+ // const parsed = JSON.parse(value) as T;
365
+ // if (Array.isArray(fallback) && !Array.isArray(parsed)) {
366
+ // console.warn('Parsed value is not an array, using fallback');
367
+ // return fallback;
368
+ // }
369
+ // return parsed;
370
+ // } catch (error) {
371
+ // console.error('Failed to parse JSON string:', error);
372
+ // return fallback;
373
+ // }
374
+ // }
375
+ // if (value == null) {
376
+ // return fallback;
377
+ // }
378
+ // return value as T;
379
+ // };
380
+ // // Dropdown Arrow Icon Component
381
+ // const DropdownArrow = ({ isOpen }: { isOpen: boolean }) => (
382
+ // <svg
383
+ // width="16"
384
+ // height="16"
385
+ // viewBox="0 0 16 16"
386
+ // style={{
387
+ // transition: 'transform 0.3s ease',
388
+ // transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)'
389
+ // }}
390
+ // >
391
+ // <path
392
+ // d="M4 6 L8 10 L12 6"
393
+ // fill="none"
394
+ // stroke="currentColor"
395
+ // strokeWidth="2"
396
+ // strokeLinecap="round"
397
+ // />
398
+ // </svg>
399
+ // );
400
+ // // Link Item Component with Dropdown Support
401
+ // const LinkItem = ({
402
+ // link,
403
+ // renderLink,
404
+ // linkPadding = '',
405
+ // activeLinkColor = 'primary',
406
+ // dropdownArrow = true,
407
+ // isMobile = false
408
+ // }: {
409
+ // link: NavLink;
410
+ // renderLink?: (link: NavLink, index: number) => React.ReactNode;
411
+ // linkPadding?: string;
412
+ // activeLinkColor?: string;
413
+ // dropdownArrow?: boolean;
414
+ // isMobile?: boolean;
415
+ // }) => {
416
+ // const [isOpen, setIsOpen] = useState(false);
417
+ // const [iconNode, setIconNode] = useState<React.ReactNode>(null);
418
+ // const timeoutRef = useRef<NodeJS.Timeout>();
419
+ // const dropdownRef = useRef<HTMLDivElement>(null);
420
+ // // Handle dynamic icon loading
421
+ // useEffect(() => {
422
+ // if (link.icon) {
423
+ // getDynamicIcon(link.icon).then(setIconNode);
424
+ // } else {
425
+ // setIconNode(null);
426
+ // }
427
+ // }, [link.icon]);
428
+ // // Close dropdown when clicking outside
429
+ // useEffect(() => {
430
+ // const handleClickOutside = (event: MouseEvent) => {
431
+ // if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
432
+ // setIsOpen(false);
433
+ // }
434
+ // };
435
+ // if (isOpen) {
436
+ // document.addEventListener('mousedown', handleClickOutside);
437
+ // }
438
+ // return () => {
439
+ // document.removeEventListener('mousedown', handleClickOutside);
440
+ // };
441
+ // }, [isOpen]);
442
+ // const hasChildren = link.children && link.children.length > 0;
443
+ // const handleMouseEnter = () => {
444
+ // if (timeoutRef.current) clearTimeout(timeoutRef.current);
445
+ // if (!isMobile && hasChildren) {
446
+ // setIsOpen(true);
447
+ // }
448
+ // };
449
+ // const handleMouseLeave = () => {
450
+ // if (!isMobile) {
451
+ // timeoutRef.current = setTimeout(() => setIsOpen(false), 150);
452
+ // }
453
+ // };
454
+ // const handleClick = (e: React.MouseEvent) => {
455
+ // if (hasChildren && isMobile) {
456
+ // e.preventDefault();
457
+ // setIsOpen(!isOpen);
458
+ // }
459
+ // };
460
+ // const linkContent = (
461
+ // <span
462
+ // className={`nav_link-content ${link.active ? 'active' : ''} ${link.className || ''}`}
463
+ // style={{
464
+ // display: 'flex',
465
+ // alignItems: 'center',
466
+ // gap: '0.5rem',
467
+ // padding: linkPadding,
468
+ // color: 'inherit',
469
+ // textDecoration: 'none'
470
+ // }}
471
+ // >
472
+ // {/* Prefix Icon */}
473
+ // {iconNode && link.iconPosition !== 'suffix' && (
474
+ // <span className="nav_link-icon prefix" style={{ display: 'flex', alignItems: 'center' }}>
475
+ // {iconNode}
476
+ // </span>
477
+ // )}
478
+ // <span className="nav_link-text">{link.label}</span>
479
+ // {/* Suffix Icon */}
480
+ // {iconNode && link.iconPosition === 'suffix' && (
481
+ // <span className="nav_link-icon suffix" style={{ display: 'flex', alignItems: 'center' }}>
482
+ // {iconNode}
483
+ // </span>
484
+ // )}
485
+ // {/* Dropdown Arrow */}
486
+ // {hasChildren && dropdownArrow && (
487
+ // <span className="nav_link-arrow" style={{ display: 'flex', alignItems: 'center' }}>
488
+ // <DropdownArrow isOpen={isOpen} />
489
+ // </span>
490
+ // )}
491
+ // </span>
492
+ // );
493
+ // // If custom renderer is provided, use it
494
+ // if (renderLink) {
495
+ // return renderLink(link, 0);
496
+ // }
497
+ // return (
498
+ // <div
499
+ // ref={dropdownRef}
500
+ // className={`nav_item ${hasChildren ? 'has-dropdown' : ''} ${isOpen ? 'dropdown-open' : ''}`}
501
+ // onMouseEnter={handleMouseEnter}
502
+ // onMouseLeave={handleMouseLeave}
503
+ // style={{ position: 'relative' }}
504
+ // >
505
+ // <a
506
+ // href={link.href}
507
+ // className={`nav_link ${link.active ? 'active' : ''}`}
508
+ // onClick={handleClick}
509
+ // style={{
510
+ // textDecoration: 'none',
511
+ // color: 'inherit',
512
+ // display: 'flex',
513
+ // alignItems: 'center'
514
+ // }}
515
+ // >
516
+ // {linkContent}
517
+ // </a>
518
+ // {/* Dropdown Menu */}
519
+ // {hasChildren && isOpen && (
520
+ // <div className={`nav_dropdown-menu ${isMobile ? 'nav_dropdown-mobile' : ''}`}>
521
+ // {link.children!.map((child, index) => (
522
+ // <LinkItem
523
+ // key={index}
524
+ // link={child}
525
+ // renderLink={renderLink}
526
+ // linkPadding={linkPadding}
527
+ // activeLinkColor={activeLinkColor}
528
+ // dropdownArrow={dropdownArrow}
529
+ // isMobile={isMobile}
530
+ // />
531
+ // ))}
532
+ // </div>
533
+ // )}
534
+ // </div>
535
+ // );
536
+ // };
537
+ // // Links component to render navigation links
538
+ // const NavLinks = ({
539
+ // links,
540
+ // renderLink,
541
+ // linkGap = '1rem',
542
+ // linkPadding = '0.5rem 1rem',
543
+ // activeLinkColor = 'primary',
544
+ // dropdownArrow = true,
545
+ // isMobile = false
546
+ // }: {
547
+ // links: NavLink[];
548
+ // renderLink?: (link: NavLink, index: number) => React.ReactNode;
549
+ // linkGap?: string;
550
+ // linkPadding?: string;
551
+ // activeLinkColor?: string;
552
+ // dropdownArrow?: boolean;
553
+ // isMobile?: boolean;
554
+ // }) => {
555
+ // if (!links || !Array.isArray(links) || links.length === 0) {
556
+ // return null;
557
+ // }
558
+ // return (
559
+ // <div
560
+ // className="nav_links"
561
+ // style={{
562
+ // display: 'flex',
563
+ // alignItems: 'center',
564
+ // gap: linkGap,
565
+ // flexDirection: isMobile ? 'column' : 'row'
566
+ // }}
567
+ // >
568
+ // {links.map((link, index) => (
569
+ // <LinkItem
570
+ // key={index}
571
+ // link={link}
572
+ // renderLink={renderLink}
573
+ // linkPadding={linkPadding}
574
+ // activeLinkColor={activeLinkColor}
575
+ // dropdownArrow={dropdownArrow}
576
+ // isMobile={isMobile}
577
+ // />
578
+ // ))}
579
+ // </div>
580
+ // );
581
+ // };
582
+ // // Logo component with multiple display options
583
+ // const Logo = ({
584
+ // type = 'text',
585
+ // text = 'MyApp',
586
+ // textSize = 'xl',
587
+ // textColor = 'primary',
588
+ // textWeight = 'bold',
589
+ // url = '',
590
+ // alt = 'Logo',
591
+ // width = '40px',
592
+ // height = 'auto',
593
+ // href = '/',
594
+ // onClick
595
+ // }: {
596
+ // type?: 'text' | 'image' | 'both' | 'none';
597
+ // text?: string;
598
+ // textSize?: string;
599
+ // textColor?: string;
600
+ // textWeight?: string;
601
+ // url?: string;
602
+ // alt?: string;
603
+ // width?: string;
604
+ // height?: string;
605
+ // href?: string;
606
+ // onClick?: () => void;
607
+ // }) => {
608
+ // if (type === 'none') return null;
609
+ // const logoContent = (
610
+ // <div className="logo-content" style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
611
+ // {/* Image Logo */}
612
+ // {(type === 'image' || type === 'both') && url && (
613
+ // <img
614
+ // src={url}
615
+ // alt={alt}
616
+ // style={{
617
+ // width,
618
+ // height,
619
+ // objectFit: 'contain',
620
+ // display: 'block'
621
+ // }}
622
+ // className="logo-image"
623
+ // />
624
+ // )}
625
+ // {/* Text Logo */}
626
+ // {(type === 'text' || type === 'both') && text && (
627
+ // <span
628
+ // className={`logo-text text-${textSize} text-${textColor} font-${textWeight}`}
629
+ // style={{
630
+ // lineHeight: 1,
631
+ // whiteSpace: 'nowrap'
632
+ // }}
633
+ // >
634
+ // {text}
635
+ // </span>
636
+ // )}
637
+ // </div>
638
+ // );
639
+ // // Wrap in link if href provided
640
+ // if (href) {
641
+ // return (
642
+ // <a
643
+ // href={href}
644
+ // onClick={onClick}
645
+ // style={{
646
+ // textDecoration: 'none',
647
+ // color: 'inherit',
648
+ // display: 'flex',
649
+ // alignItems: 'center'
650
+ // }}
651
+ // className="logo-link"
652
+ // >
653
+ // {logoContent}
654
+ // </a>
655
+ // );
656
+ // }
657
+ // return (
658
+ // <div
659
+ // onClick={onClick}
660
+ // style={{ cursor: onClick ? 'pointer' : 'default' }}
661
+ // className="logo-container"
662
+ // >
663
+ // {logoContent}
664
+ // </div>
665
+ // );
666
+ // };
667
+ // export default function AppBar(localProps: NavbarProps) {
668
+ // // Use component configuration with variant support
669
+ // const { mergeWithLocal } = useComponentConfiguration('AppBar', localProps.variant);
670
+ // // Merge with config - LOCAL PROPS OVERRIDE CONFIG
671
+ // const { props: mergedProps } = mergeWithLocal(localProps);
672
+ // // Parse link props if they're strings
673
+ // const parsedLeftLinks = parseIfString<NavLink[]>(mergedProps.leftLinks, []);
674
+ // const parsedCenterLinks = parseIfString<NavLink[]>(mergedProps.centerLinks, []);
675
+ // const parsedRightLinks = parseIfString<NavLink[]>(mergedProps.rightLinks, []);
676
+ // // Use mergedProps directly
677
+ // const final = mergedProps;
678
+ // const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
679
+ // const [isMobileScreen, setIsMobileScreen] = useState(false);
680
+ // const pathname = usePathname();
681
+ // const toggleMenu = () => setIsMobileMenuOpen((prev) => !prev);
682
+ // const closeMenu = () => setIsMobileMenuOpen(false);
683
+ // useEffect(() => {
684
+ // const handleResize = () => {
685
+ // const isMobile = window.innerWidth < (final.mobileMenuBreakpoint || 992);
686
+ // setIsMobileScreen(isMobile);
687
+ // if (!isMobile) {
688
+ // closeMenu(); // close on larger screens
689
+ // }
690
+ // };
691
+ // handleResize(); // initial check
692
+ // window.addEventListener('resize', handleResize);
693
+ // return () => window.removeEventListener('resize', handleResize);
694
+ // }, [final.mobileMenuBreakpoint]);
695
+ // // Automatically close menu on route (pathname) change
696
+ // useEffect(() => {
697
+ // closeMenu();
698
+ // }, [pathname]);
699
+ // const Trigger = ({ isOpen }: { isOpen: boolean }) => {
700
+ // return <Hamburger isOpen={isOpen} />;
701
+ // };
702
+ // // Enhanced left section with logo customization
703
+ // const renderLeftSection = () => {
704
+ // // If custom left content is provided, use it (overrides everything)
705
+ // if (final.left) return final.left;
706
+ // // Render logo based on configuration
707
+ // const shouldRenderLogo = final.logoType && final.logoType !== 'none';
708
+ // const hasLeftLinks = parsedLeftLinks.length > 0;
709
+ // return (
710
+ // <div className="left-section" style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>
711
+ // {/* Logo */}
712
+ // {shouldRenderLogo && (
713
+ // <Logo
714
+ // type={final.logoType}
715
+ // text={final.logoText}
716
+ // textSize={final.logoTextSize}
717
+ // textColor={final.logoTextColor}
718
+ // textWeight={final.logoTextWeight}
719
+ // url={final.logoUrl}
720
+ // alt={final.logoAlt}
721
+ // width={final.logoWidth}
722
+ // height={final.logoHeight}
723
+ // href={final.logoHref}
724
+ // onClick={final.onLogoClick}
725
+ // />
726
+ // )}
727
+ // {/* Left navigation links (appear next to logo) */}
728
+ // {hasLeftLinks && !isMobileScreen && (
729
+ // <NavLinks
730
+ // links={parsedLeftLinks}
731
+ // renderLink={final.renderLink}
732
+ // linkGap={final.linkGap}
733
+ // linkPadding={final.linkPadding}
734
+ // activeLinkColor={final.activeLinkColor}
735
+ // dropdownArrow={final.dropdownArrow}
736
+ // />
737
+ // )}
738
+ // </div>
739
+ // );
740
+ // };
741
+ // const renderCenterSection = () => {
742
+ // if (final.center) return final.center;
743
+ // if (parsedCenterLinks.length > 0 && !isMobileScreen) {
744
+ // return (
745
+ // <NavLinks
746
+ // links={parsedCenterLinks}
747
+ // renderLink={final.renderLink}
748
+ // linkGap={final.linkGap}
749
+ // linkPadding={final.linkPadding}
750
+ // activeLinkColor={final.activeLinkColor}
751
+ // dropdownArrow={final.dropdownArrow}
752
+ // />
753
+ // );
754
+ // }
755
+ // return null;
756
+ // };
757
+ // const renderRightSection = () => {
758
+ // if (final.right) return final.right;
759
+ // if (parsedRightLinks.length > 0 && !isMobileScreen) {
760
+ // return (
761
+ // <NavLinks
762
+ // links={parsedRightLinks}
763
+ // renderLink={final.renderLink}
764
+ // linkGap={final.linkGap}
765
+ // linkPadding={final.linkPadding}
766
+ // activeLinkColor={final.activeLinkColor}
767
+ // dropdownArrow={final.dropdownArrow}
768
+ // />
769
+ // );
770
+ // }
771
+ // return null;
772
+ // };
773
+ // // Mobile menu content
774
+ // const renderMobileMenu = () => {
775
+ // if (!isMobileScreen || !isMobileMenuOpen) return null;
776
+ // const allLinks = [...parsedLeftLinks, ...parsedCenterLinks, ...parsedRightLinks];
777
+ // return (
778
+ // <div className="nav_mobile-menu">
779
+ // <NavLinks
780
+ // links={allLinks}
781
+ // renderLink={final.renderLink}
782
+ // linkGap="0.5rem"
783
+ // linkPadding="1rem"
784
+ // activeLinkColor={final.activeLinkColor}
785
+ // dropdownArrow={final.dropdownArrow}
786
+ // isMobile={true}
787
+ // />
788
+ // </div>
789
+ // );
790
+ // };
791
+ // return (
792
+ // <>
793
+ // <nav
794
+ // id='appBar'
795
+ // className={`navigation-bar
796
+ // ${isMobileMenuOpen ? 'navbar-mobile-open' : ''}
797
+ // ${final.funcss || ''}
798
+ // ${ final.testing ? "" : final.fixedTop ? 'fixed_top_navbar' : ''}
799
+ // ${final.sideBar ? 'there_is_sidebar' : ''}
800
+ // ${final.transparent ? 'transparent' : ''}
801
+ // ${final.fixedBottom ? 'fixedBottom' : ''}
802
+ // `}
803
+ // style={{
804
+ // padding: `${final.padding || ''}`,
805
+ // justifyContent: `${final.justify || ''}`,
806
+ // }}
807
+ // >
808
+ // <div className="logoWrapper">
809
+ // {renderLeftSection()}
810
+ // {isMobileScreen && isMobileMenuOpen && (
811
+ // <div className="hover-text-error pointer _closeNav" onClick={closeMenu}>
812
+ // <Trigger isOpen={isMobileMenuOpen} />
813
+ // </div>
814
+ // )}
815
+ // </div>
816
+ // <div className="linkWrapper">
817
+ // {renderCenterSection()}
818
+ // </div>
819
+ // <div className="linkWrapper">
820
+ // {renderRightSection()}
821
+ // </div>
822
+ // {isMobileScreen && !isMobileMenuOpen && (
823
+ // <>
824
+ // {final.hasSidebar ?
825
+ // <span className="sidebar-trigger pointer hover-text-primary" onClick={final.openSidebar}>
826
+ // {final.sidebarTrigger || <Trigger isOpen={final.sidebarOpen} />}
827
+ // </span>
828
+ // :
829
+ // <span className="sidebar-trigger pointer hover-text-primary" onClick={toggleMenu}>
830
+ // {final.sidebarTrigger || <Trigger isOpen={isMobileMenuOpen} />}
831
+ // </span>
832
+ // }
833
+ // </>
834
+ // )}
835
+ // </nav>
836
+ // {renderMobileMenu()}
837
+ // </>
838
+ // );
839
+ // }
@@ -56,8 +56,10 @@ var RichText = function (_a) {
56
56
  var isInitialMount = (0, react_1.useRef)(true);
57
57
  var isTypingRef = (0, react_1.useRef)(false);
58
58
  var typingTimeoutRef = (0, react_1.useRef)(null);
59
+ var isUserChangeRef = (0, react_1.useRef)(false);
59
60
  var _f = (0, react_1.useState)(false), isFocused = _f[0], setIsFocused = _f[1];
60
61
  var lastKnownValueRef = (0, react_1.useRef)(value);
62
+ var quillInstanceRef = (0, react_1.useRef)(null);
61
63
  // Update refs when props change
62
64
  (0, react_1.useEffect)(function () {
63
65
  onChangeRef.current = onChange;
@@ -71,6 +73,12 @@ var RichText = function (_a) {
71
73
  placeholder: placeholder,
72
74
  modules: modules || defaultModules,
73
75
  }), quill = _g.quill, quillRef = _g.quillRef;
76
+ // Store quill instance in ref
77
+ (0, react_1.useEffect)(function () {
78
+ if (quill) {
79
+ quillInstanceRef.current = quill;
80
+ }
81
+ }, [quill]);
74
82
  // Debounced onChange handler
75
83
  var debouncedOnChange = (0, react_1.useCallback)(function (content) {
76
84
  if (debounceTimeoutRef.current) {
@@ -81,10 +89,11 @@ var RichText = function (_a) {
81
89
  }, 300); // 300ms debounce delay
82
90
  }, []);
83
91
  // Handle text change with debouncing
84
- var handleTextChange = (0, react_1.useCallback)(function () {
85
- var _a, _b, _c;
86
- if (!quill)
92
+ var handleTextChange = (0, react_1.useCallback)(function (delta, oldDelta, source) {
93
+ var _a, _b;
94
+ if (!quill || source !== 'user')
87
95
  return;
96
+ isUserChangeRef.current = true;
88
97
  isTypingRef.current = true;
89
98
  // Reset typing flag after 500ms of inactivity
90
99
  if (typingTimeoutRef.current) {
@@ -94,17 +103,23 @@ var RichText = function (_a) {
94
103
  isTypingRef.current = false;
95
104
  }, 500);
96
105
  var plainText = quill.getText().trim();
106
+ var currentHTML = quill.root.innerHTML;
97
107
  // --- Enforce maxValue if needed ---
98
108
  if (maxValueRef.current && plainText.length > maxValueRef.current) {
99
- var truncated = plainText.slice(0, maxValueRef.current);
100
- quill.setText(truncated);
101
- quill.setSelection(truncated.length);
109
+ // Store current selection
110
+ var selection = quill.getSelection();
111
+ // Remove the extra content
112
+ quill.deleteText(maxValueRef.current, plainText.length - maxValueRef.current);
113
+ // Restore selection if it was at the end
114
+ if (selection && selection.index > maxValueRef.current) {
115
+ quill.setSelection(maxValueRef.current);
116
+ }
102
117
  return; // Don't trigger onChange for truncated text
103
118
  }
104
119
  // --- Clean the HTML output ---
105
- var cleanedHTML = (_c = (_b = (_a = quill.root.innerHTML) === null || _a === void 0 ? void 0 : _a.replace(/<p><br><\/p>/g, '') // remove empty paragraphs
106
- ) === null || _b === void 0 ? void 0 : _b.replace(/\s+/g, ' ') // collapse multiple spaces
107
- ) === null || _c === void 0 ? void 0 : _c.trim(); // remove leading/trailing spaces
120
+ var cleanedHTML = (_b = (_a = currentHTML === null || currentHTML === void 0 ? void 0 : currentHTML.replace(/<p><br><\/p>/g, '') // remove empty paragraphs
121
+ ) === null || _a === void 0 ? void 0 : _a.replace(/\s+/g, ' ') // collapse multiple spaces
122
+ ) === null || _b === void 0 ? void 0 : _b.trim(); // remove leading/trailing spaces
108
123
  lastKnownValueRef.current = cleanedHTML || '';
109
124
  debouncedOnChange(lastKnownValueRef.current);
110
125
  }, [quill, debouncedOnChange]);
@@ -116,11 +131,13 @@ var RichText = function (_a) {
116
131
  // Handle focus
117
132
  var handleFocus = (0, react_1.useCallback)(function () {
118
133
  setIsFocused(true);
134
+ isUserChangeRef.current = false;
119
135
  }, []);
120
136
  // Handle blur
121
137
  var handleBlur = (0, react_1.useCallback)(function () {
122
138
  setIsFocused(false);
123
139
  isTypingRef.current = false;
140
+ isUserChangeRef.current = false;
124
141
  }, []);
125
142
  // Set up event listeners
126
143
  (0, react_1.useEffect)(function () {
@@ -156,7 +173,8 @@ var RichText = function (_a) {
156
173
  if (isInitialMount.current && value) {
157
174
  // clean before setting editor value
158
175
  var cleanedValue = (_b = (_a = value === null || value === void 0 ? void 0 : value.replace(/<p><br><\/p>/g, '')) === null || _a === void 0 ? void 0 : _a.replace(/\s+/g, ' ')) === null || _b === void 0 ? void 0 : _b.trim();
159
- quill.root.innerHTML = cleanedValue || '';
176
+ // Use quill.clipboard.dangerouslyPasteHTML to preserve formatting
177
+ quill.clipboard.dangerouslyPasteHTML(0, cleanedValue || '');
160
178
  lastKnownValueRef.current = cleanedValue || '';
161
179
  isInitialMount.current = false;
162
180
  }
@@ -169,24 +187,50 @@ var RichText = function (_a) {
169
187
  // Skip if value is the same as current editor content
170
188
  if (value === lastKnownValueRef.current)
171
189
  return;
172
- // Don't update while user is typing or editor is focused
173
- if (isTypingRef.current || isFocused) {
190
+ // Don't update while user is typing or editor is focused with recent user changes
191
+ if (isTypingRef.current || (isFocused && isUserChangeRef.current)) {
174
192
  return;
175
193
  }
176
194
  // clean before setting editor value
177
195
  var cleanedValue = (_b = (_a = value === null || value === void 0 ? void 0 : value.replace(/<p><br><\/p>/g, '')) === null || _a === void 0 ? void 0 : _a.replace(/\s+/g, ' ')) === null || _b === void 0 ? void 0 : _b.trim();
178
196
  if (quill.root.innerHTML !== cleanedValue) {
179
- quill.root.innerHTML = cleanedValue || '';
180
- lastKnownValueRef.current = cleanedValue || '';
197
+ // Store current selection
198
+ var selection_1 = quill.getSelection();
199
+ // Get current HTML content
200
+ var currentHTML = quill.root.innerHTML;
201
+ // Calculate the difference
202
+ var currentLength = quill.getLength();
203
+ // Only update if there's a meaningful difference
204
+ if (cleanedValue !== currentHTML) {
205
+ // Replace content using quill's API
206
+ quill.clipboard.dangerouslyPasteHTML(0, cleanedValue || '');
207
+ lastKnownValueRef.current = cleanedValue || '';
208
+ // Try to restore selection position if we had one
209
+ if (selection_1) {
210
+ // Set a small timeout to ensure the content is updated
211
+ setTimeout(function () {
212
+ var newLength = quill.getLength();
213
+ var newIndex = Math.min(selection_1.index, newLength);
214
+ quill.setSelection(newIndex);
215
+ }, 0);
216
+ }
217
+ }
181
218
  }
182
219
  }, [quill, value, isFocused]);
183
220
  var insertEmoji = (0, react_1.useCallback)(function (emoji) {
184
221
  if (quill && savedRange.current) {
185
222
  var plainText = quill.getText().trim();
186
223
  if (!maxValueRef.current || plainText.length + emoji.length <= maxValueRef.current) {
187
- var selection = quill.getSelection();
188
- quill.insertText(savedRange.current.index, emoji);
189
- quill.setSelection(savedRange.current.index + emoji.length);
224
+ // Use the current selection if available, otherwise use saved range
225
+ var currentSelection = quill.getSelection();
226
+ var insertIndex = currentSelection ? currentSelection.index : savedRange.current.index;
227
+ quill.insertText(insertIndex, emoji);
228
+ quill.setSelection(insertIndex + emoji.length);
229
+ // Update saved range
230
+ savedRange.current = {
231
+ index: insertIndex + emoji.length,
232
+ length: 0
233
+ };
190
234
  }
191
235
  }
192
236
  }, [quill]);
@@ -224,6 +268,281 @@ var RichText = function (_a) {
224
268
  };
225
269
  exports.default = RichText;
226
270
  // 'use client';
271
+ // import React, { useEffect, useRef, useCallback, useState } from 'react';
272
+ // import { useQuill } from 'react-quilljs';
273
+ // import { MdOutlineEmojiEmotions } from 'react-icons/md';
274
+ // import { AllEmojis } from '../../utils/Emojis';
275
+ // import Dropdown from '../drop/Dropdown';
276
+ // import RowFlex from '../specials/RowFlex';
277
+ // import ToolTip from '../tooltip/ToolTip';
278
+ // import Circle from '../specials/Circle';
279
+ // import Tip from '../tooltip/Tip';
280
+ // import Flex from '../flex/Flex';
281
+ // type RangeStatic = {
282
+ // index: number;
283
+ // length: number;
284
+ // };
285
+ // interface RichTextProps {
286
+ // value: string;
287
+ // onChange: (content: string) => void;
288
+ // showEmojis?: boolean;
289
+ // placeholder?: string;
290
+ // afterEmoji?: React.ReactNode;
291
+ // funcss?: string;
292
+ // modules?: any;
293
+ // theme?: 'bubble' | 'snow';
294
+ // fontFamily?: string;
295
+ // maxValue?: number;
296
+ // }
297
+ // const RichText: React.FC<RichTextProps> = ({
298
+ // value,
299
+ // onChange,
300
+ // showEmojis = false,
301
+ // placeholder = 'Write something...',
302
+ // afterEmoji,
303
+ // funcss = '',
304
+ // modules,
305
+ // theme = 'bubble',
306
+ // fontFamily,
307
+ // maxValue,
308
+ // }) => {
309
+ // const savedRange = useRef<RangeStatic | null>(null);
310
+ // const onChangeRef = useRef(onChange);
311
+ // const maxValueRef = useRef(maxValue);
312
+ // const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null);
313
+ // const isInitialMount = useRef(true);
314
+ // const isTypingRef = useRef(false);
315
+ // const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
316
+ // const [isFocused, setIsFocused] = useState(false);
317
+ // const lastKnownValueRef = useRef(value);
318
+ // // Update refs when props change
319
+ // useEffect(() => {
320
+ // onChangeRef.current = onChange;
321
+ // maxValueRef.current = maxValue;
322
+ // }, [onChange, maxValue]);
323
+ // const defaultModules = {
324
+ // toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]],
325
+ // };
326
+ // const { quill, quillRef } = useQuill({
327
+ // theme,
328
+ // placeholder,
329
+ // modules: modules || defaultModules,
330
+ // });
331
+ // // Debounced onChange handler
332
+ // const debouncedOnChange = useCallback((content: string) => {
333
+ // if (debounceTimeoutRef.current) {
334
+ // clearTimeout(debounceTimeoutRef.current);
335
+ // }
336
+ // debounceTimeoutRef.current = setTimeout(() => {
337
+ // onChangeRef.current(content);
338
+ // }, 300); // 300ms debounce delay
339
+ // }, []);
340
+ // // Handle text change with debouncing
341
+ // const handleTextChange = useCallback(() => {
342
+ // if (!quill) return;
343
+ // isTypingRef.current = true;
344
+ // // Reset typing flag after 500ms of inactivity
345
+ // if (typingTimeoutRef.current) {
346
+ // clearTimeout(typingTimeoutRef.current);
347
+ // }
348
+ // typingTimeoutRef.current = setTimeout(() => {
349
+ // isTypingRef.current = false;
350
+ // }, 500);
351
+ // const plainText = quill.getText().trim();
352
+ // // --- Enforce maxValue if needed ---
353
+ // if (maxValueRef.current && plainText.length > maxValueRef.current) {
354
+ // const truncated = plainText.slice(0, maxValueRef.current);
355
+ // quill.setText(truncated);
356
+ // quill.setSelection(truncated.length);
357
+ // return; // Don't trigger onChange for truncated text
358
+ // }
359
+ // // --- Clean the HTML output ---
360
+ // const cleanedHTML = quill.root.innerHTML
361
+ // ?.replace(/<p><br><\/p>/g, '') // remove empty paragraphs
362
+ // ?.replace(/\s+/g, ' ') // collapse multiple spaces
363
+ // ?.trim(); // remove leading/trailing spaces
364
+ // lastKnownValueRef.current = cleanedHTML || '';
365
+ // debouncedOnChange(lastKnownValueRef.current);
366
+ // }, [quill, debouncedOnChange]);
367
+ // // Handle selection change
368
+ // const handleSelectionChange = useCallback((range: RangeStatic | null) => {
369
+ // if (range) savedRange.current = range;
370
+ // }, []);
371
+ // // Handle focus
372
+ // const handleFocus = useCallback(() => {
373
+ // setIsFocused(true);
374
+ // }, []);
375
+ // // Handle blur
376
+ // const handleBlur = useCallback(() => {
377
+ // setIsFocused(false);
378
+ // isTypingRef.current = false;
379
+ // }, []);
380
+ // // Set up event listeners
381
+ // useEffect(() => {
382
+ // if (!quill) return;
383
+ // const editor = quill.root;
384
+ // quill.on('selection-change', handleSelectionChange);
385
+ // quill.on('text-change', handleTextChange);
386
+ // // Add focus/blur event listeners
387
+ // editor.addEventListener('focus', handleFocus);
388
+ // editor.addEventListener('blur', handleBlur);
389
+ // return () => {
390
+ // quill.off('selection-change', handleSelectionChange);
391
+ // quill.off('text-change', handleTextChange);
392
+ // // Remove focus/blur event listeners
393
+ // editor.removeEventListener('focus', handleFocus);
394
+ // editor.removeEventListener('blur', handleBlur);
395
+ // // Clean up timeouts
396
+ // if (debounceTimeoutRef.current) {
397
+ // clearTimeout(debounceTimeoutRef.current);
398
+ // }
399
+ // if (typingTimeoutRef.current) {
400
+ // clearTimeout(typingTimeoutRef.current);
401
+ // }
402
+ // };
403
+ // }, [quill, handleSelectionChange, handleTextChange, handleFocus, handleBlur]);
404
+ // // Initialize editor with initial value
405
+ // useEffect(() => {
406
+ // if (!quill) return;
407
+ // // Only set initial value on first mount
408
+ // if (isInitialMount.current && value) {
409
+ // // clean before setting editor value
410
+ // const cleanedValue = value
411
+ // ?.replace(/<p><br><\/p>/g, '')
412
+ // ?.replace(/\s+/g, ' ')
413
+ // ?.trim();
414
+ // quill.root.innerHTML = cleanedValue || '';
415
+ // lastKnownValueRef.current = cleanedValue || '';
416
+ // isInitialMount.current = false;
417
+ // }
418
+ // }, [quill, value]);
419
+ // // Update editor when value prop changes (for external updates)
420
+ // useEffect(() => {
421
+ // if (!quill || isInitialMount.current) return;
422
+ // // Skip if value is the same as current editor content
423
+ // if (value === lastKnownValueRef.current) return;
424
+ // // Don't update while user is typing or editor is focused
425
+ // if (isTypingRef.current || isFocused) {
426
+ // return;
427
+ // }
428
+ // // clean before setting editor value
429
+ // const cleanedValue = value
430
+ // ?.replace(/<p><br><\/p>/g, '')
431
+ // ?.replace(/\s+/g, ' ')
432
+ // ?.trim();
433
+ // if (quill.root.innerHTML !== cleanedValue) {
434
+ // quill.root.innerHTML = cleanedValue || '';
435
+ // lastKnownValueRef.current = cleanedValue || '';
436
+ // }
437
+ // }, [quill, value, isFocused]);
438
+ // const insertEmoji = useCallback((emoji: string) => {
439
+ // if (quill && savedRange.current) {
440
+ // const plainText = quill.getText().trim();
441
+ // if (!maxValueRef.current || plainText.length + emoji.length <= maxValueRef.current) {
442
+ // const selection = quill.getSelection();
443
+ // quill.insertText(savedRange.current.index, emoji);
444
+ // quill.setSelection(savedRange.current.index + emoji.length);
445
+ // }
446
+ // }
447
+ // }, [quill]);
448
+ // const renderEmojiSection = useCallback((title: string, emojis: string[]) => (
449
+ // <>
450
+ // <div className="mb-2 mt-2 text-sm">{title}</div>
451
+ // <RowFlex gap={0.3}>
452
+ // {emojis.map((emoji, i) => (
453
+ // <span
454
+ // key={i}
455
+ // className="h6 pointer"
456
+ // onClick={() => insertEmoji(emoji)}
457
+ // >
458
+ // {emoji}
459
+ // </span>
460
+ // ))}
461
+ // </RowFlex>
462
+ // </>
463
+ // ), [insertEmoji]);
464
+ // return (
465
+ // <div
466
+ // className={`fit round-edge ${funcss}`}
467
+ // style={{ position: 'relative', overflow: 'visible' }}
468
+ // >
469
+ // <div id="editor-container" className="bubble-editor-container p-0">
470
+ // <div
471
+ // ref={quillRef}
472
+ // className={theme === 'bubble' ? 'bubble-editor' : 'snow-editor'}
473
+ // style={{
474
+ // fontFamily: fontFamily || 'inherit',
475
+ // }}
476
+ // />
477
+ // </div>
478
+ // {(showEmojis || maxValue) && (
479
+ // <div
480
+ // className="p-1"
481
+ // style={{ height: 'fit-content', top: `calc(100%)`, width: '100%' }}
482
+ // >
483
+ // <Flex justify="space-between" gap={1} alignItems="center" width="100%">
484
+ // {(showEmojis || afterEmoji) ? (
485
+ // <div>
486
+ // <Flex width="100%" gap={0.5} alignItems="center">
487
+ // {showEmojis && (
488
+ // <Dropdown
489
+ // closableOnlyOutside
490
+ // button={
491
+ // <ToolTip>
492
+ // <Circle size={2} funcss="bg border">
493
+ // <MdOutlineEmojiEmotions />
494
+ // </Circle>
495
+ // <Tip
496
+ // tip="top"
497
+ // animation="ScaleUp"
498
+ // duration={0.5}
499
+ // content="Emojis"
500
+ // />
501
+ // </ToolTip>
502
+ // }
503
+ // items={[
504
+ // {
505
+ // label: (
506
+ // <div
507
+ // className="w-200 h-200"
508
+ // style={{ overflowY: 'auto' }}
509
+ // >
510
+ // {renderEmojiSection('❤️ Smileys & People', AllEmojis.Smiley)}
511
+ // {renderEmojiSection('👍 Gestures & Body Parts', AllEmojis.Gesture)}
512
+ // {renderEmojiSection('🔥 Symbols & Expressions', AllEmojis.Symbols)}
513
+ // {renderEmojiSection('🚀 Travel, Objects & Activities', AllEmojis.Travel)}
514
+ // {renderEmojiSection('👨‍👩‍👧‍👦 People & Professions', AllEmojis.People)}
515
+ // {renderEmojiSection('🐶 Animals & Nature', AllEmojis.Animals)}
516
+ // </div>
517
+ // ),
518
+ // },
519
+ // ]}
520
+ // />
521
+ // )}
522
+ // {afterEmoji}
523
+ // </Flex>
524
+ // </div>
525
+ // ) : (
526
+ // <div />
527
+ // )}
528
+ // {maxValue && quill ? (
529
+ // <div className="text-xs text-right">
530
+ // <span className="text-primary">
531
+ // {quill.getText().trim().length}
532
+ // </span>
533
+ // /{maxValue}
534
+ // </div>
535
+ // ) : (
536
+ // <div />
537
+ // )}
538
+ // </Flex>
539
+ // </div>
540
+ // )}
541
+ // </div>
542
+ // );
543
+ // };
544
+ // export default RichText;
545
+ // 'use client';
227
546
  // import React, { useEffect, useRef } from 'react';
228
547
  // import { useQuill } from 'react-quilljs';
229
548
  // import { MdOutlineEmojiEmotions } from 'react-icons/md';