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 +20 -0
- package/package.json +1 -1
- package/ui/div/Div.d.ts +5 -1
- package/ui/div/Div.js +3 -3
- package/ui/modal/Modal.js +4 -4
- package/ui/products/ProductCard.js +106 -4
- package/ui/products/ProductDetail.js +1 -1
- package/ui/richtext/RichText.js +307 -30
- package/ui/vista/Vista.d.ts +1 -1
- package/ui/vista/Vista.js +766 -12
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
|
+
"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",
|
|
63
|
-
React.createElement("div", __assign({
|
|
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:
|
|
91
|
+
maxHeight: "fit-content",
|
|
92
92
|
width: width || '100%',
|
|
93
|
-
height:
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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",
|
package/ui/richtext/RichText.js
CHANGED
|
@@ -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
|
|
69
|
+
var _g = (0, react_quilljs_1.useQuill)({
|
|
57
70
|
theme: theme,
|
|
58
71
|
placeholder: placeholder,
|
|
59
72
|
modules: modules || defaultModules,
|
|
60
|
-
}), quill =
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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 (!
|
|
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;
|
package/ui/vista/Vista.d.ts
CHANGED
|
@@ -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;
|