funuicss 3.9.2 β†’ 3.9.4

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/css/fun.css CHANGED
@@ -4356,6 +4356,7 @@ opacity: 1;
4356
4356
  }
4357
4357
  .modal-body {
4358
4358
  height: 100%;
4359
+
4359
4360
  }
4360
4361
 
4361
4362
  .modal-action {
@@ -5476,6 +5477,25 @@ background-color: rgba(0, 0, 0, 0.2);
5476
5477
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
5477
5478
  }
5478
5479
 
5480
+
5481
+
5482
+ /* Optional: Add loading animation */
5483
+ @keyframes imageLoading {
5484
+ 0% { opacity: 0.3; }
5485
+ 50% { opacity: 0.7; }
5486
+ 100% { opacity: 0.3; }
5487
+ }
5488
+
5489
+ .funui_store_no-image {
5490
+ display: flex;
5491
+ align-items: center;
5492
+ justify-content: center;
5493
+ width: 100%;
5494
+ height: 100%;
5495
+ background-color: #f5f5f5;
5496
+ animation: imageLoading 1.5s infinite;
5497
+ }
5498
+
5479
5499
  /* Badges */
5480
5500
  .funui_store_product-badges {
5481
5501
  position: absolute;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.9.2",
2
+ "version": "3.9.4",
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",
package/ui/div/Div.d.ts CHANGED
@@ -18,6 +18,10 @@ type DivProps = {
18
18
  ref?: React.Ref<HTMLDivElement>;
19
19
  customStyle?: React.CSSProperties;
20
20
  onClick?: React.MouseEventHandler<HTMLDivElement>;
21
+ onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
22
+ onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
23
+ onMouseOver?: React.MouseEventHandler<HTMLDivElement>;
24
+ onMouseOut?: React.MouseEventHandler<HTMLDivElement>;
21
25
  };
22
- declare const Div: ({ children, funcss, content, minHeight, maxHeight, maxWidth, minWidth, height, width, padding, className, style, margin, id, fit, ref, customStyle, ...rest }: DivProps) => React.JSX.Element;
26
+ declare const Div: ({ children, funcss, content, minHeight, maxHeight, maxWidth, minWidth, height, width, padding, className, style, margin, id, fit, ref, customStyle, onClick, onMouseEnter, onMouseLeave, onMouseOver, onMouseOut, ...rest }: DivProps) => React.JSX.Element;
23
27
  export default Div;
package/ui/div/Div.js CHANGED
@@ -58,8 +58,8 @@ var __rest = (this && this.__rest) || function (s, e) {
58
58
  Object.defineProperty(exports, "__esModule", { value: true });
59
59
  var React = __importStar(require("react"));
60
60
  var Div = function (_a) {
61
- var children = _a.children, funcss = _a.funcss, content = _a.content, minHeight = _a.minHeight, maxHeight = _a.maxHeight, maxWidth = _a.maxWidth, minWidth = _a.minWidth, height = _a.height, width = _a.width, padding = _a.padding, className = _a.className, style = _a.style, margin = _a.margin, id = _a.id, fit = _a.fit, ref = _a.ref, customStyle = _a.customStyle, rest = __rest(_a, ["children", "funcss", "content", "minHeight", "maxHeight", "maxWidth", "minWidth", "height", "width", "padding", "className", "style", "margin", "id", "fit", "ref", "customStyle"]);
62
- return (React.createElement("div", null,
63
- React.createElement("div", __assign({ ref: ref, className: "".concat(fit ? 'width-100-p height-100-p' : '', " ").concat(funcss, " ").concat(className || ''), style: __assign(__assign({ height: height || '', maxHeight: maxHeight || '', minHeight: minHeight || '', maxWidth: maxWidth || '', minWidth: minWidth || '', width: width || '', padding: padding || '', margin: margin || '' }, style), customStyle), id: id }, rest), content || children)));
61
+ var children = _a.children, funcss = _a.funcss, content = _a.content, minHeight = _a.minHeight, maxHeight = _a.maxHeight, maxWidth = _a.maxWidth, minWidth = _a.minWidth, height = _a.height, width = _a.width, padding = _a.padding, className = _a.className, style = _a.style, margin = _a.margin, id = _a.id, fit = _a.fit, ref = _a.ref, customStyle = _a.customStyle, onClick = _a.onClick, onMouseEnter = _a.onMouseEnter, onMouseLeave = _a.onMouseLeave, onMouseOver = _a.onMouseOver, onMouseOut = _a.onMouseOut, rest = __rest(_a, ["children", "funcss", "content", "minHeight", "maxHeight", "maxWidth", "minWidth", "height", "width", "padding", "className", "style", "margin", "id", "fit", "ref", "customStyle", "onClick", "onMouseEnter", "onMouseLeave", "onMouseOver", "onMouseOut"]);
62
+ return (React.createElement("div", { ref: ref, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseOver: onMouseOver, onMouseOut: onMouseOut, onClick: onClick },
63
+ React.createElement("div", __assign({ className: "".concat(fit ? 'width-100-p height-100-p' : '', " ").concat(funcss, " ").concat(className || ''), style: __assign(__assign({ height: height || '', maxHeight: maxHeight || '', minHeight: minHeight || '', maxWidth: maxWidth || '', minWidth: minWidth || '', width: width || '', padding: padding || '', margin: margin || '' }, style), customStyle), id: id }, rest), content || children)));
64
64
  };
65
65
  exports.default = Div;
package/ui/modal/Modal.js CHANGED
@@ -62,10 +62,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
62
62
  exports.default = Modal;
63
63
  var React = __importStar(require("react"));
64
64
  var Header_1 = __importDefault(require("./Header"));
65
- var Content_1 = __importDefault(require("./Content"));
66
65
  var Action_1 = __importDefault(require("./Action"));
67
66
  var pi_1 = require("react-icons/pi");
68
67
  var Button_1 = __importDefault(require("../button/Button"));
68
+ var View_1 = __importDefault(require("../view/View"));
69
69
  function Modal(_a) {
70
70
  var children = _a.children, funcss = _a.funcss, animation = _a.animation, duration = _a.duration, open = _a.open, setOpen = _a.setOpen, maxWidth = _a.maxWidth, maxHeight = _a.maxHeight, okIcon = _a.okIcon, height = _a.height, _b = _a.hideClose, hideClose = _b === void 0 ? false : _b, width = _a.width, _c = _a.backdrop, backdrop = _c === void 0 ? false : _c, title = _a.title, titlecss = _a.titlecss, body = _a.body, bodycss = _a.bodycss, footer = _a.footer, footercss = _a.footercss, close = _a.close, closecss = _a.closecss, position = _a.position, id = _a.id, flat = _a.flat, onOk = _a.onOk, // πŸ‘ˆ added
71
71
  onOkText = _a.onOkText, // πŸ‘ˆ added
@@ -88,14 +88,14 @@ function Modal(_a) {
88
88
  React.createElement("div", __assign({ className: "modal-content ".concat(funcss || '', " ").concat(flat ? 'flat' : ''), style: {
89
89
  animation: "".concat(duration || 0.3, "s ").concat(animation || 'SlideDown'),
90
90
  maxWidth: maxWidth || "700px",
91
- maxHeight: maxHeight || "fit-content",
91
+ maxHeight: "fit-content",
92
92
  width: width || '100%',
93
- height: height || "fit-content",
93
+ height: "fit-content",
94
94
  } }, rest),
95
95
  title && (React.createElement(Header_1.default, { funcss: titlecss || '', title: title, close: !hideClose ?
96
96
  React.createElement("div", { onClick: function () { return setOpen(false); }, className: "".concat(closecss || '', " pointer hover-text-error") }, close || React.createElement(pi_1.PiX, { size: 25 }))
97
97
  : "" })),
98
- React.createElement(Content_1.default, { funcss: bodycss || '' }, body || children),
98
+ React.createElement(View_1.default, { funcss: "modal-body ".concat(bodycss || ''), height: "100%", overflow: 'auto', maxHeight: height || maxHeight || "100%" }, body || children),
99
99
  footer ? (React.createElement(Action_1.default, { funcss: footercss || '' }, footer)) : (React.createElement(Action_1.default, { funcss: 'text-right' },
100
100
  React.createElement(Button_1.default, { bg: 'success', endIcon: okIcon || React.createElement(pi_1.PiPaperPlaneRight, null), raised: true, onClick: handleOkClick }, onOkText || 'OK'))))));
101
101
  }
@@ -1,30 +1,132 @@
1
1
  "use strict";
2
2
  'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
37
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
38
+ if (ar || !(i in from)) {
39
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
40
+ ar[i] = from[i];
41
+ }
42
+ }
43
+ return to.concat(ar || Array.prototype.slice.call(from));
44
+ };
3
45
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
46
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
47
  };
6
48
  Object.defineProperty(exports, "__esModule", { value: true });
7
- var react_1 = __importDefault(require("react"));
49
+ var react_1 = __importStar(require("react"));
8
50
  var Div_1 = __importDefault(require("../div/Div"));
9
51
  var Text_1 = __importDefault(require("../text/Text"));
10
52
  var Flex_1 = __importDefault(require("../flex/Flex"));
11
53
  var ProductCard = function (_a) {
12
- var _b;
13
- var product = _a.product, _c = _a.currency, currency = _c === void 0 ? '$' : _c, onClick = _a.onClick, onAddToCart = _a.onAddToCart, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.funcss, funcss = _e === void 0 ? '' : _e, _f = _a.showBadges, showBadges = _f === void 0 ? true : _f;
54
+ var product = _a.product, _b = _a.currency, currency = _b === void 0 ? '$' : _b, onClick = _a.onClick, onAddToCart = _a.onAddToCart, _c = _a.className, className = _c === void 0 ? '' : _c, _d = _a.funcss, funcss = _d === void 0 ? '' : _d, _e = _a.showBadges, showBadges = _e === void 0 ? true : _e;
14
55
  var hasDiscount = product.comparePrice && product.comparePrice > product.price;
15
56
  var discountPercent = hasDiscount
16
57
  ? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
17
58
  : 0;
59
+ // Track which image is currently displayed
60
+ var _f = (0, react_1.useState)(0), currentImageIndex = _f[0], setCurrentImageIndex = _f[1];
61
+ var _g = (0, react_1.useState)([]), imagesLoaded = _g[0], setImagesLoaded = _g[1];
62
+ // Check if product has multiple images
63
+ var hasMultipleImages = product.images && product.images.length > 1;
64
+ // Handle image preloading
65
+ (0, react_1.useEffect)(function () {
66
+ if (!product.images || product.images.length === 0)
67
+ return;
68
+ // Track loaded images
69
+ var loadedStatus = new Array(product.images.length).fill(false);
70
+ setImagesLoaded(loadedStatus);
71
+ // Preload all images
72
+ product.images.forEach(function (src, index) {
73
+ var img = new Image();
74
+ img.src = src;
75
+ img.onload = function () {
76
+ setImagesLoaded(function (prev) {
77
+ var updated = __spreadArray([], prev, true);
78
+ updated[index] = true;
79
+ return updated;
80
+ });
81
+ };
82
+ });
83
+ }, [product.images]);
18
84
  var handleClick = function () {
19
85
  onClick === null || onClick === void 0 ? void 0 : onClick(product);
20
86
  };
87
+ var handleMouseEnter = function () {
88
+ if (hasMultipleImages && product.images && product.images.length > 1) {
89
+ // Switch to next image (or first if at the end)
90
+ setCurrentImageIndex(function (prev) {
91
+ return prev === product.images.length - 1 ? 0 : prev + 1;
92
+ });
93
+ }
94
+ };
95
+ var handleMouseLeave = function () {
96
+ // Reset to first image when mouse leaves
97
+ setCurrentImageIndex(0);
98
+ };
21
99
  var getDisplayPrice = function () {
22
100
  var price = product.price || 0;
23
101
  var productCurrency = product.currency || currency;
24
102
  return "".concat(productCurrency).concat(price.toFixed(2));
25
103
  };
26
104
  return (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-card ".concat(className, " ").concat(funcss), onClick: handleClick, customStyle: { cursor: 'pointer' } },
27
- react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container round-edge" }, ((_b = product.images) === null || _b === void 0 ? void 0 : _b[0]) ? (react_1.default.createElement("img", { src: product.images[0], alt: product.name, loading: "lazy", className: "funui_store_product-image" })) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
105
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container round-edge", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, customStyle: { position: 'relative', overflow: 'hidden' } }, product.images && product.images.length > 0 ? (react_1.default.createElement(react_1.default.Fragment, null,
106
+ react_1.default.createElement("img", { src: product.images[0], alt: product.name, loading: "lazy", className: "funui_store_product-image", style: {
107
+ position: 'absolute',
108
+ top: 0,
109
+ left: 0,
110
+ width: '100%',
111
+ height: '100%',
112
+ objectFit: 'cover',
113
+ opacity: currentImageIndex === 0 ? 1 : 0,
114
+ transition: 'opacity 0.3s ease-in-out',
115
+ zIndex: 1
116
+ } }),
117
+ product.images.slice(1).map(function (imageSrc, index) { return (react_1.default.createElement("img", { key: "preload-".concat(index + 1), src: imageSrc, alt: "".concat(product.name, " - View ").concat(index + 2), loading: "lazy", style: {
118
+ position: 'absolute',
119
+ top: 0,
120
+ left: 0,
121
+ width: '100%',
122
+ height: '100%',
123
+ objectFit: 'cover',
124
+ opacity: currentImageIndex === index + 1 ? 1 : 0,
125
+ transition: 'opacity 0.3s ease-in-out',
126
+ zIndex: 2
127
+ } })); }),
128
+ (!product.images[0] || imagesLoaded[0] === false) && (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
129
+ react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "sm" }))))) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
28
130
  react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "sm" })))),
29
131
  react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-info " },
30
132
  product.category && (react_1.default.createElement(Text_1.default, { size: 'xs', opacity: 4, uppercase: true }, product.category)),
@@ -190,7 +190,7 @@ var ProductDetail = function (_a) {
190
190
  react_1.default.createElement(Text_1.default, { size: 'xs', opacity: 4 },
191
191
  product.stock,
192
192
  " units available"))),
193
- ((product.colors && product.colors.length > 0) || (product.sizes && product.sizes.length > 0)) && (react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1, direction: "column" },
193
+ ((product.colors && product.colors.length > 0) || (product.sizes && product.sizes.length > 0)) && (react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1 },
194
194
  product.colors && product.colors.length > 0 && (react_1.default.createElement("div", { className: "col" },
195
195
  react_1.default.createElement(Text_1.default, { size: "sm", weight: 500, funcss: "mb-1" },
196
196
  "Color",
@@ -50,65 +50,149 @@ var Flex_1 = __importDefault(require("../flex/Flex"));
50
50
  var RichText = function (_a) {
51
51
  var value = _a.value, onChange = _a.onChange, _b = _a.showEmojis, showEmojis = _b === void 0 ? false : _b, _c = _a.placeholder, placeholder = _c === void 0 ? 'Write something...' : _c, afterEmoji = _a.afterEmoji, _d = _a.funcss, funcss = _d === void 0 ? '' : _d, modules = _a.modules, _e = _a.theme, theme = _e === void 0 ? 'bubble' : _e, fontFamily = _a.fontFamily, maxValue = _a.maxValue;
52
52
  var savedRange = (0, react_1.useRef)(null);
53
+ var onChangeRef = (0, react_1.useRef)(onChange);
54
+ var maxValueRef = (0, react_1.useRef)(maxValue);
55
+ var debounceTimeoutRef = (0, react_1.useRef)(null);
56
+ var isInitialMount = (0, react_1.useRef)(true);
57
+ var isTypingRef = (0, react_1.useRef)(false);
58
+ var typingTimeoutRef = (0, react_1.useRef)(null);
59
+ var _f = (0, react_1.useState)(false), isFocused = _f[0], setIsFocused = _f[1];
60
+ var lastKnownValueRef = (0, react_1.useRef)(value);
61
+ // Update refs when props change
62
+ (0, react_1.useEffect)(function () {
63
+ onChangeRef.current = onChange;
64
+ maxValueRef.current = maxValue;
65
+ }, [onChange, maxValue]);
53
66
  var defaultModules = {
54
67
  toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]],
55
68
  };
56
- var _f = (0, react_quilljs_1.useQuill)({
69
+ var _g = (0, react_quilljs_1.useQuill)({
57
70
  theme: theme,
58
71
  placeholder: placeholder,
59
72
  modules: modules || defaultModules,
60
- }), quill = _f.quill, quillRef = _f.quillRef;
73
+ }), quill = _g.quill, quillRef = _g.quillRef;
74
+ // Debounced onChange handler
75
+ var debouncedOnChange = (0, react_1.useCallback)(function (content) {
76
+ if (debounceTimeoutRef.current) {
77
+ clearTimeout(debounceTimeoutRef.current);
78
+ }
79
+ debounceTimeoutRef.current = setTimeout(function () {
80
+ onChangeRef.current(content);
81
+ }, 300); // 300ms debounce delay
82
+ }, []);
83
+ // Handle text change with debouncing
84
+ var handleTextChange = (0, react_1.useCallback)(function () {
85
+ var _a, _b, _c;
86
+ if (!quill)
87
+ return;
88
+ isTypingRef.current = true;
89
+ // Reset typing flag after 500ms of inactivity
90
+ if (typingTimeoutRef.current) {
91
+ clearTimeout(typingTimeoutRef.current);
92
+ }
93
+ typingTimeoutRef.current = setTimeout(function () {
94
+ isTypingRef.current = false;
95
+ }, 500);
96
+ var plainText = quill.getText().trim();
97
+ // --- Enforce maxValue if needed ---
98
+ if (maxValueRef.current && plainText.length > maxValueRef.current) {
99
+ var truncated = plainText.slice(0, maxValueRef.current);
100
+ quill.setText(truncated);
101
+ quill.setSelection(truncated.length);
102
+ return; // Don't trigger onChange for truncated text
103
+ }
104
+ // --- 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
108
+ lastKnownValueRef.current = cleanedHTML || '';
109
+ debouncedOnChange(lastKnownValueRef.current);
110
+ }, [quill, debouncedOnChange]);
111
+ // Handle selection change
112
+ var handleSelectionChange = (0, react_1.useCallback)(function (range) {
113
+ if (range)
114
+ savedRange.current = range;
115
+ }, []);
116
+ // Handle focus
117
+ var handleFocus = (0, react_1.useCallback)(function () {
118
+ setIsFocused(true);
119
+ }, []);
120
+ // Handle blur
121
+ var handleBlur = (0, react_1.useCallback)(function () {
122
+ setIsFocused(false);
123
+ isTypingRef.current = false;
124
+ }, []);
125
+ // Set up event listeners
61
126
  (0, react_1.useEffect)(function () {
62
127
  if (!quill)
63
128
  return;
64
- var handleSelectionChange = function (range) {
65
- if (range)
66
- savedRange.current = range;
67
- };
68
- var handleTextChange = function () {
69
- var _a, _b, _c;
70
- if (!quill)
71
- return;
72
- var plainText = quill.getText().trim();
73
- // --- Enforce maxValue if needed ---
74
- if (maxValue && plainText.length > maxValue) {
75
- var truncated = plainText.slice(0, maxValue);
76
- quill.setText(truncated);
77
- quill.setSelection(truncated.length);
78
- }
79
- // --- Clean the HTML output ---
80
- var cleanedHTML = (_c = (_b = (_a = quill.root.innerHTML) === null || _a === void 0 ? void 0 : _a.replace(/<p><br><\/p>/g, '') // remove empty paragraphs
81
- ) === null || _b === void 0 ? void 0 : _b.replace(/\s+/g, ' ') // collapse multiple spaces
82
- ) === null || _c === void 0 ? void 0 : _c.trim(); // remove leading/trailing spaces
83
- onChange(cleanedHTML || '');
84
- };
129
+ var editor = quill.root;
85
130
  quill.on('selection-change', handleSelectionChange);
86
131
  quill.on('text-change', handleTextChange);
132
+ // Add focus/blur event listeners
133
+ editor.addEventListener('focus', handleFocus);
134
+ editor.addEventListener('blur', handleBlur);
87
135
  return function () {
88
136
  quill.off('selection-change', handleSelectionChange);
89
137
  quill.off('text-change', handleTextChange);
138
+ // Remove focus/blur event listeners
139
+ editor.removeEventListener('focus', handleFocus);
140
+ editor.removeEventListener('blur', handleBlur);
141
+ // Clean up timeouts
142
+ if (debounceTimeoutRef.current) {
143
+ clearTimeout(debounceTimeoutRef.current);
144
+ }
145
+ if (typingTimeoutRef.current) {
146
+ clearTimeout(typingTimeoutRef.current);
147
+ }
90
148
  };
91
- }, [quill, onChange, maxValue]);
149
+ }, [quill, handleSelectionChange, handleTextChange, handleFocus, handleBlur]);
150
+ // Initialize editor with initial value
92
151
  (0, react_1.useEffect)(function () {
93
152
  var _a, _b;
94
- if (quill && value !== quill.root.innerHTML) {
153
+ if (!quill)
154
+ return;
155
+ // Only set initial value on first mount
156
+ if (isInitialMount.current && value) {
95
157
  // clean before setting editor value
96
158
  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();
97
159
  quill.root.innerHTML = cleanedValue || '';
160
+ lastKnownValueRef.current = cleanedValue || '';
161
+ isInitialMount.current = false;
98
162
  }
99
163
  }, [quill, value]);
100
- var insertEmoji = function (emoji) {
164
+ // Update editor when value prop changes (for external updates)
165
+ (0, react_1.useEffect)(function () {
166
+ var _a, _b;
167
+ if (!quill || isInitialMount.current)
168
+ return;
169
+ // Skip if value is the same as current editor content
170
+ if (value === lastKnownValueRef.current)
171
+ return;
172
+ // Don't update while user is typing or editor is focused
173
+ if (isTypingRef.current || isFocused) {
174
+ return;
175
+ }
176
+ // clean before setting editor value
177
+ 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
+ if (quill.root.innerHTML !== cleanedValue) {
179
+ quill.root.innerHTML = cleanedValue || '';
180
+ lastKnownValueRef.current = cleanedValue || '';
181
+ }
182
+ }, [quill, value, isFocused]);
183
+ var insertEmoji = (0, react_1.useCallback)(function (emoji) {
101
184
  if (quill && savedRange.current) {
102
185
  var plainText = quill.getText().trim();
103
- if (!maxValue || plainText.length + emoji.length <= maxValue) {
186
+ if (!maxValueRef.current || plainText.length + emoji.length <= maxValueRef.current) {
187
+ var selection = quill.getSelection();
104
188
  quill.insertText(savedRange.current.index, emoji);
105
189
  quill.setSelection(savedRange.current.index + emoji.length);
106
190
  }
107
191
  }
108
- };
109
- var renderEmojiSection = function (title, emojis) { return (react_1.default.createElement(react_1.default.Fragment, null,
192
+ }, [quill]);
193
+ var renderEmojiSection = (0, react_1.useCallback)(function (title, emojis) { return (react_1.default.createElement(react_1.default.Fragment, null,
110
194
  react_1.default.createElement("div", { className: "mb-2 mt-2 text-sm" }, title),
111
- react_1.default.createElement(RowFlex_1.default, { gap: 0.3 }, emojis.map(function (emoji, i) { return (react_1.default.createElement("span", { key: i, className: "h6 pointer", onClick: function () { return insertEmoji(emoji); } }, emoji)); })))); };
195
+ react_1.default.createElement(RowFlex_1.default, { gap: 0.3 }, emojis.map(function (emoji, i) { return (react_1.default.createElement("span", { key: i, className: "h6 pointer", onClick: function () { return insertEmoji(emoji); } }, emoji)); })))); }, [insertEmoji]);
112
196
  return (react_1.default.createElement("div", { className: "fit round-edge ".concat(funcss), style: { position: 'relative', overflow: 'visible' } },
113
197
  react_1.default.createElement("div", { id: "editor-container", className: "bubble-editor-container p-0" },
114
198
  react_1.default.createElement("div", { ref: quillRef, className: theme === 'bubble' ? 'bubble-editor' : 'snow-editor', style: {
@@ -139,3 +223,196 @@ var RichText = function (_a) {
139
223
  maxValue)) : (react_1.default.createElement("div", null)))))));
140
224
  };
141
225
  exports.default = RichText;
226
+ // 'use client';
227
+ // import React, { useEffect, useRef } from 'react';
228
+ // import { useQuill } from 'react-quilljs';
229
+ // import { MdOutlineEmojiEmotions } from 'react-icons/md';
230
+ // import { AllEmojis } from '../../utils/Emojis';
231
+ // import Dropdown from '../drop/Dropdown';
232
+ // import RowFlex from '../specials/RowFlex';
233
+ // import ToolTip from '../tooltip/ToolTip';
234
+ // import Circle from '../specials/Circle';
235
+ // import Tip from '../tooltip/Tip';
236
+ // import Flex from '../flex/Flex';
237
+ // type RangeStatic = {
238
+ // index: number;
239
+ // length: number;
240
+ // };
241
+ // interface RichTextProps {
242
+ // value: string;
243
+ // onChange: (content: string) => void;
244
+ // showEmojis?: boolean;
245
+ // placeholder?: string;
246
+ // afterEmoji?: React.ReactNode;
247
+ // funcss?: string;
248
+ // modules?: any;
249
+ // theme?: 'bubble' | 'snow';
250
+ // fontFamily?: string;
251
+ // maxValue?: number;
252
+ // }
253
+ // const RichText: React.FC<RichTextProps> = ({
254
+ // value,
255
+ // onChange,
256
+ // showEmojis = false,
257
+ // placeholder = 'Write something...',
258
+ // afterEmoji,
259
+ // funcss = '',
260
+ // modules,
261
+ // theme = 'bubble',
262
+ // fontFamily,
263
+ // maxValue,
264
+ // }) => {
265
+ // const savedRange = useRef<RangeStatic | null>(null);
266
+ // const defaultModules = {
267
+ // toolbar: [['bold', 'italic', 'underline'], [{ list: 'bullet' }]],
268
+ // };
269
+ // const { quill, quillRef } = useQuill({
270
+ // theme,
271
+ // placeholder,
272
+ // modules: modules || defaultModules,
273
+ // });
274
+ // useEffect(() => {
275
+ // if (!quill) return;
276
+ // const handleSelectionChange = (range: RangeStatic | null) => {
277
+ // if (range) savedRange.current = range;
278
+ // };
279
+ // const handleTextChange = () => {
280
+ // if (!quill) return;
281
+ // const plainText = quill.getText().trim();
282
+ // // --- Enforce maxValue if needed ---
283
+ // if (maxValue && plainText.length > maxValue) {
284
+ // const truncated = plainText.slice(0, maxValue);
285
+ // quill.setText(truncated);
286
+ // quill.setSelection(truncated.length);
287
+ // }
288
+ // // --- Clean the HTML output ---
289
+ // const cleanedHTML = quill.root.innerHTML
290
+ // ?.replace(/<p><br><\/p>/g, '') // remove empty paragraphs
291
+ // ?.replace(/\s+/g, ' ') // collapse multiple spaces
292
+ // ?.trim(); // remove leading/trailing spaces
293
+ // onChange(cleanedHTML || '');
294
+ // };
295
+ // quill.on('selection-change', handleSelectionChange);
296
+ // quill.on('text-change', handleTextChange);
297
+ // return () => {
298
+ // quill.off('selection-change', handleSelectionChange);
299
+ // quill.off('text-change', handleTextChange);
300
+ // };
301
+ // }, [quill, onChange, maxValue]);
302
+ // useEffect(() => {
303
+ // if (quill && value !== quill.root.innerHTML) {
304
+ // // clean before setting editor value
305
+ // const cleanedValue = value
306
+ // ?.replace(/<p><br><\/p>/g, '')
307
+ // ?.replace(/\s+/g, ' ')
308
+ // ?.trim();
309
+ // quill.root.innerHTML = cleanedValue || '';
310
+ // }
311
+ // }, [quill, value]);
312
+ // const insertEmoji = (emoji: string) => {
313
+ // if (quill && savedRange.current) {
314
+ // const plainText = quill.getText().trim();
315
+ // if (!maxValue || plainText.length + emoji.length <= maxValue) {
316
+ // quill.insertText(savedRange.current.index, emoji);
317
+ // quill.setSelection(savedRange.current.index + emoji.length);
318
+ // }
319
+ // }
320
+ // };
321
+ // const renderEmojiSection = (title: string, emojis: string[]) => (
322
+ // <>
323
+ // <div className="mb-2 mt-2 text-sm">{title}</div>
324
+ // <RowFlex gap={0.3}>
325
+ // {emojis.map((emoji, i) => (
326
+ // <span
327
+ // key={i}
328
+ // className="h6 pointer"
329
+ // onClick={() => insertEmoji(emoji)}
330
+ // >
331
+ // {emoji}
332
+ // </span>
333
+ // ))}
334
+ // </RowFlex>
335
+ // </>
336
+ // );
337
+ // return (
338
+ // <div
339
+ // className={`fit round-edge ${funcss}`}
340
+ // style={{ position: 'relative', overflow: 'visible' }}
341
+ // >
342
+ // <div id="editor-container" className="bubble-editor-container p-0">
343
+ // <div
344
+ // ref={quillRef}
345
+ // className={theme === 'bubble' ? 'bubble-editor' : 'snow-editor'}
346
+ // style={{
347
+ // fontFamily: fontFamily || 'inherit',
348
+ // }}
349
+ // />
350
+ // </div>
351
+ // {(showEmojis || maxValue) && (
352
+ // <div
353
+ // className="p-1"
354
+ // style={{ height: 'fit-content', top: `calc(100%)`, width: '100%' }}
355
+ // >
356
+ // <Flex justify="space-between" gap={1} alignItems="center" width="100%">
357
+ // {(showEmojis || afterEmoji) ? (
358
+ // <div>
359
+ // <Flex width="100%" gap={0.5} alignItems="center">
360
+ // {showEmojis && (
361
+ // <Dropdown
362
+ // closableOnlyOutside
363
+ // openOnHover={false}
364
+ // button={
365
+ // <ToolTip>
366
+ // <Circle size={2} funcss="bg border">
367
+ // <MdOutlineEmojiEmotions />
368
+ // </Circle>
369
+ // <Tip
370
+ // tip="top"
371
+ // animation="ScaleUp"
372
+ // duration={0.5}
373
+ // content="Emojis"
374
+ // />
375
+ // </ToolTip>
376
+ // }
377
+ // items={[
378
+ // {
379
+ // label: (
380
+ // <div
381
+ // className="w-200 h-200"
382
+ // style={{ overflowY: 'auto' }}
383
+ // >
384
+ // {renderEmojiSection('❀️ Smileys & People', AllEmojis.Smiley)}
385
+ // {renderEmojiSection('πŸ‘ Gestures & Body Parts', AllEmojis.Gesture)}
386
+ // {renderEmojiSection('πŸ”₯ Symbols & Expressions', AllEmojis.Symbols)}
387
+ // {renderEmojiSection('πŸš€ Travel, Objects & Activities', AllEmojis.Travel)}
388
+ // {renderEmojiSection('πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ People & Professions', AllEmojis.People)}
389
+ // {renderEmojiSection('🐢 Animals & Nature', AllEmojis.Animals)}
390
+ // </div>
391
+ // ),
392
+ // },
393
+ // ]}
394
+ // />
395
+ // )}
396
+ // {afterEmoji}
397
+ // </Flex>
398
+ // </div>
399
+ // ) : (
400
+ // <div />
401
+ // )}
402
+ // {maxValue && quill ? (
403
+ // <div className="text-xs text-right">
404
+ // <span className="text-primary">
405
+ // {quill.getText().trim().length}
406
+ // </span>
407
+ // /{maxValue}
408
+ // </div>
409
+ // ) : (
410
+ // <div />
411
+ // )}
412
+ // </Flex>
413
+ // </div>
414
+ // )}
415
+ // </div>
416
+ // );
417
+ // };
418
+ // export default RichText;
@@ -5,7 +5,7 @@ type VistaProps = {
5
5
  gradientOverlay?: boolean;
6
6
  gradientColor?: string;
7
7
  gradientOpacity?: number;
8
- gradientDirection?: 'linear' | 'radial';
8
+ gradientDirection?: 'linear' | 'radial' | 'even';
9
9
  gradientLinearDirection?: 'to right' | 'to left' | 'to top' | 'to bottom' | 'to top right' | 'to top left' | 'to bottom right' | 'to bottom left';
10
10
  backgroundMedia?: 'none' | 'image' | 'video';
11
11
  backgroundImage?: string;