UNPKG

sgod-library-frontend

Version:
913 lines (888 loc) 99.6 kB
'use strict'; var React = require('react'); var classNames = require('classnames'); var mitt = require('mitt'); var clsx = require('clsx'); var tailwindMerge = require('tailwind-merge'); var sonner = require('sonner'); var jwt = require('jsonwebtoken'); var z = require('zod'); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var Button = function (_a) { var children = _a.children, _b = _a.variant, variant = _b === void 0 ? 'primary' : _b, _c = _a.size, size = _c === void 0 ? 'md' : _c, _d = _a.isLoading, isLoading = _d === void 0 ? false : _d, _e = _a.isFullWidth, isFullWidth = _e === void 0 ? false : _e, leftIcon = _a.leftIcon, rightIcon = _a.rightIcon, className = _a.className, disabled = _a.disabled, rest = __rest(_a, ["children", "variant", "size", "isLoading", "isFullWidth", "leftIcon", "rightIcon", "className", "disabled"]); var baseClasses = "inline-flex items-center justify-center font-medium rounded transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2"; var variantClasses = { primary: "bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500", secondary: "bg-secondary-200 text-secondary-800 hover:bg-secondary-300 focus:ring-secondary-400", outline: "border border-primary-600 text-primary-600 hover:bg-primary-50 focus:ring-primary-500", ghost: "text-primary-600 hover:bg-primary-50 focus:ring-primary-500", error: "bg-error text-white hover:bg-red-600 focus:ring-red-500", }; var sizeClasses = { sm: "px-3 py-1.5 text-sm", md: "px-4 py-2 text-base", lg: "px-6 py-3 text-lg", }; var loadingClasses = isLoading ? "opacity-80 cursor-not-allowed" : ""; var widthClasses = isFullWidth ? "w-full" : ""; var disabledClasses = disabled ? "opacity-50 cursor-not-allowed" : ""; var buttonClasses = classNames(baseClasses, variantClasses[variant], sizeClasses[size], loadingClasses, widthClasses, disabledClasses, className); return (React.createElement("button", __assign({ className: buttonClasses, disabled: disabled || isLoading }, rest), isLoading && (React.createElement("svg", { className: "animate-spinner -ml-1 mr-2 h-4 w-4 text-current", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, React.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), React.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }))), !isLoading && leftIcon && React.createElement("span", { className: "mr-2" }, leftIcon), children, !isLoading && rightIcon && React.createElement("span", { className: "ml-2" }, rightIcon))); }; var Input = React.forwardRef(function (_a, ref) { var className = _a.className, label = _a.label, error = _a.error, helperText = _a.helperText, _b = _a.size, size = _b === void 0 ? 'md' : _b, _c = _a.fullWidth, fullWidth = _c === void 0 ? false : _c, leftIcon = _a.leftIcon, rightIcon = _a.rightIcon, _d = _a.isLoading, isLoading = _d === void 0 ? false : _d, disabled = _a.disabled, required = _a.required, id = _a.id, rest = __rest(_a, ["className", "label", "error", "helperText", "size", "fullWidth", "leftIcon", "rightIcon", "isLoading", "disabled", "required", "id"]); var inputId = id || "input-".concat(Math.random().toString(36).substr(2, 9)); var sizeClasses = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-4 py-3 text-lg', }; var containerClasses = classNames('flex flex-col', { 'w-full': fullWidth, 'opacity-60 cursor-not-allowed': disabled, }); var inputContainerClasses = classNames('relative flex items-center border rounded focus-within:ring-2 focus-within:ring-offset-1 transition-all', { 'border-red-500 focus-within:ring-red-500': error, 'border-gray-300 focus-within:border-primary-500 focus-within:ring-primary-500': !error, 'bg-gray-100': disabled, }); var inputClasses = classNames('w-full outline-none bg-transparent', sizeClasses[size], { 'pl-9': leftIcon, 'pr-9': rightIcon || isLoading, }, className); return (React.createElement("div", { className: containerClasses }, label && (React.createElement("label", { htmlFor: inputId, className: "mb-1 text-sm font-medium text-gray-700" }, label, required && React.createElement("span", { className: "text-red-500 ml-1" }, "*"))), React.createElement("div", { className: inputContainerClasses }, leftIcon && (React.createElement("span", { className: "absolute left-3 flex items-center pointer-events-none text-gray-500" }, leftIcon)), React.createElement("input", __assign({ ref: ref, id: inputId, disabled: disabled || isLoading, required: required, className: inputClasses, "aria-invalid": error ? 'true' : 'false', "aria-describedby": error ? "".concat(inputId, "-error") : helperText ? "".concat(inputId, "-helper") : undefined }, rest)), isLoading ? (React.createElement("span", { className: "absolute right-3 flex items-center pointer-events-none text-gray-500" }, React.createElement("svg", { className: "animate-spinner h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, React.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), React.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })))) : rightIcon ? (React.createElement("span", { className: "absolute right-3 flex items-center pointer-events-none text-gray-500" }, rightIcon)) : null), error && (React.createElement("p", { id: "".concat(inputId, "-error"), className: "mt-1 text-sm text-red-500" }, error)), helperText && !error && (React.createElement("p", { id: "".concat(inputId, "-helper"), className: "mt-1 text-sm text-gray-500" }, helperText)))); }); Input.displayName = 'Input'; var Skeleton = function (_a) { var className = _a.className, _b = _a.width, width = _b === void 0 ? '100%' : _b, _c = _a.height, height = _c === void 0 ? '1rem' : _c, _d = _a.borderRadius, borderRadius = _d === void 0 ? '0.25rem' : _d; var style = { width: typeof width === 'number' ? "".concat(width, "px") : width, height: typeof height === 'number' ? "".concat(height, "px") : height, borderRadius: borderRadius, }; return (React.createElement("div", { className: classNames('shimmer', className), style: style, role: "status", "aria-busy": "true", "aria-live": "polite" }, React.createElement("span", { className: "sr-only" }, "\u0110ang t\u1EA3i..."))); }; var Grid = function (_a) { var children = _a.children, _b = _a.container, container = _b === void 0 ? false : _b, _c = _a.item, item = _c === void 0 ? false : _c, cols = _a.cols, sm = _a.sm, md = _a.md, lg = _a.lg, xl = _a.xl, _d = _a.spacing, spacing = _d === void 0 ? 4 : _d, justifyContent = _a.justifyContent, alignItems = _a.alignItems, _e = _a.direction, direction = _e === void 0 ? 'row' : _e, _f = _a.wrap, wrap = _f === void 0 ? 'wrap' : _f, className = _a.className; var spacingClass = container ? "gap-".concat(spacing) : ''; // Cột mặc định (cho màn hình nhỏ nhất) var colsClasses = cols ? "grid-cols-".concat(cols) : ''; // Responsive grid columns var smColsClasses = sm ? "sm:grid-cols-".concat(sm) : ''; var mdColsClasses = md ? "md:grid-cols-".concat(md) : ''; var lgColsClasses = lg ? "lg:grid-cols-".concat(lg) : ''; var xlColsClasses = xl ? "xl:grid-cols-".concat(xl) : ''; // Item spanning var itemColSpan = item && cols ? "col-span-".concat(cols) : ''; var itemSmColSpan = item && sm ? "sm:col-span-".concat(sm) : ''; var itemMdColSpan = item && md ? "md:col-span-".concat(md) : ''; var itemLgColSpan = item && lg ? "lg:col-span-".concat(lg) : ''; var itemXlColSpan = item && xl ? "xl:col-span-".concat(xl) : ''; // Alignment var justifyContentClass = justifyContent ? "justify-".concat(justifyContent) : ''; var alignItemsClass = alignItems ? "items-".concat(alignItems) : ''; var directionClass = "flex-".concat(direction); var wrapClass = "flex-".concat(wrap); return (React.createElement("div", { className: classNames( // Nếu là container, sử dụng grid container && 'grid', // Nếu là container, áp dụng gap spacingClass, // Áp dụng số cột nếu là container container && colsClasses, container && smColsClasses, container && mdColsClasses, container && lgColsClasses, container && xlColsClasses, // Áp dụng span columns nếu là item item && itemColSpan, item && itemSmColSpan, item && itemMdColSpan, item && itemLgColSpan, item && itemXlColSpan, // Alignment justifyContentClass, alignItemsClass, container && directionClass, container && wrapClass, className) }, children)); }; var getIconSize = function (size) { switch (size) { case 'xs': return 'w-3 h-3'; // 12px case 'sm': return 'w-4 h-4'; // 16px case 'md': return 'w-5 h-5'; // 20px case 'lg': return 'w-6 h-6'; // 24px case 'xl': return 'w-8 h-8'; // 32px case '2xl': return 'w-10 h-10'; // 40px default: return 'w-5 h-5'; // 20px } }; // Bộ icons được định nghĩa ở đây // Sử dụng cách tiếp cận "render props" để có thể dễ dàng mở rộng var icons = { 'check': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }))); }, }, 'x': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z", clipRule: "evenodd" }))); }, }, 'info': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }))); }, }, 'warning': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }))); }, }, 'error': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }))); }, }, 'success': { outline: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", className: className }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" }))); }, solid: function (_a) { var className = _a.className; return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: className }, React.createElement("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }))); }, }, }; var Icon = function (_a) { var _b; var name = _a.name, _c = _a.size, size = _c === void 0 ? 'md' : _c, _d = _a.variant, variant = _d === void 0 ? 'outline' : _d, color = _a.color, className = _a.className; // Chọn icon từ bộ icons var IconComponent = (_b = icons[name]) === null || _b === void 0 ? void 0 : _b[variant]; if (!IconComponent) { console.warn("Icon \"".concat(name, "\" with variant \"").concat(variant, "\" not found")); return null; } var sizeClass = getIconSize(size); var colorClass = color ? "text-".concat(color) : ''; return (React.createElement(IconComponent, { className: classNames(sizeClass, colorClass, className) })); }; var Typography = function (_a) { var _b = _a.variant, variant = _b === void 0 ? 'body1' : _b, _c = _a.align, align = _c === void 0 ? 'inherit' : _c, _d = _a.color, color = _d === void 0 ? 'inherit' : _d, weight = _a.weight, children = _a.children, className = _a.className, component = _a.component, _e = _a.gutterBottom, gutterBottom = _e === void 0 ? false : _e, _f = _a.noWrap, noWrap = _f === void 0 ? false : _f; // Xác định component mặc định dựa vào variant var Component = component || getComponentFromVariant(variant); var variantClasses = { h1: 'text-5xl font-heading font-bold leading-tight', h2: 'text-4xl font-heading font-bold leading-tight', h3: 'text-3xl font-heading font-bold leading-tight', h4: 'text-2xl font-heading font-bold leading-tight', h5: 'text-xl font-heading font-medium leading-tight', h6: 'text-lg font-heading font-medium leading-tight', subtitle1: 'text-lg font-body leading-normal', subtitle2: 'text-base font-body font-medium leading-normal', body1: 'text-base font-body leading-normal', body2: 'text-sm font-body leading-normal', caption: 'text-xs font-body leading-normal', overline: 'text-xs font-body uppercase tracking-wider leading-normal', }; var alignClasses = { inherit: '', left: 'text-left', center: 'text-center', right: 'text-right', justify: 'text-justify', }; var colorClasses = { inherit: '', primary: 'text-primary-600', secondary: 'text-secondary-600', success: 'text-success-600', error: 'text-error-600', warning: 'text-warning-600', info: 'text-info-600', neutral: 'text-neutral-600', }; var weightClasses = { regular: 'font-regular', medium: 'font-medium', bold: 'font-bold', }; var classes = classNames(variantClasses[variant], alignClasses[align], colorClasses[color], weight && weightClasses[weight], gutterBottom && 'mb-2', noWrap && 'truncate', className); return (React.createElement(Component, { className: classes }, children)); }; // Helper function để xác định component mặc định dựa vào variant function getComponentFromVariant(variant) { switch (variant) { case 'h1': return 'h1'; case 'h2': return 'h2'; case 'h3': return 'h3'; case 'h4': return 'h4'; case 'h5': return 'h5'; case 'h6': return 'h6'; case 'subtitle1': case 'subtitle2': return 'h6'; case 'body1': case 'body2': return 'p'; case 'caption': case 'overline': return 'span'; default: return 'p'; } } var Card = function (_a) { var children = _a.children, className = _a.className, title = _a.title, subtitle = _a.subtitle, footer = _a.footer, _b = _a.elevation, elevation = _b === void 0 ? 'sm' : _b, _c = _a.bordered, bordered = _c === void 0 ? false : _c, _d = _a.rounded, rounded = _d === void 0 ? 'md' : _d, _e = _a.padding, padding = _e === void 0 ? 'md' : _e; var elevationClasses = { none: '', sm: 'shadow-sm', md: 'shadow-md', lg: 'shadow-lg', }; var roundedClasses = { none: 'rounded-none', sm: 'rounded-sm', md: 'rounded-md', lg: 'rounded-lg', full: 'rounded-full', }; var paddingClasses = { none: 'p-0', sm: 'p-3', md: 'p-4', lg: 'p-6', }; var headerClasses = classNames('border-b border-gray-200', { 'pb-3 mb-3': padding !== 'none', 'pb-2 mb-2': padding === 'sm', 'pb-4 mb-4': padding === 'lg', }); var containerClasses = classNames('bg-white', elevationClasses[elevation], roundedClasses[rounded], paddingClasses[padding], { 'border border-gray-200': bordered, }, className); return (React.createElement("div", { className: containerClasses }, (title || subtitle) && (React.createElement("div", { className: headerClasses }, title && React.createElement("h3", { className: "text-lg font-medium text-gray-900" }, title), subtitle && React.createElement("p", { className: "text-sm text-gray-500" }, subtitle))), React.createElement("div", { className: "card-content" }, children), footer && (React.createElement("div", { className: classNames('border-t border-gray-200', { 'pt-3 mt-3': padding !== 'none', 'pt-2 mt-2': padding === 'sm', 'pt-4 mt-4': padding === 'lg', }) }, footer)))); }; var EmptyState = function (_a) { var title = _a.title, description = _a.description, icon = _a.icon, action = _a.action, className = _a.className, _b = _a.size, size = _b === void 0 ? 'md' : _b; var sizeClasses = { sm: { container: 'p-4', icon: 'w-10 h-10', title: 'text-base', description: 'text-xs', }, md: { container: 'p-6', icon: 'w-16 h-16', title: 'text-lg', description: 'text-sm', }, lg: { container: 'p-8', icon: 'w-20 h-20', title: 'text-xl', description: 'text-base', }, }; var selectedSize = sizeClasses[size]; return (React.createElement("div", { className: classNames('flex flex-col items-center justify-center text-center bg-gray-50 border border-dashed border-gray-300 rounded-lg', selectedSize.container, className) }, icon && (React.createElement("div", { className: classNames('text-gray-400 mb-3', selectedSize.icon) }, icon)), React.createElement("h3", { className: classNames('font-medium text-gray-900', selectedSize.title) }, title), description && (React.createElement("p", { className: classNames('text-gray-500 mt-1', selectedSize.description) }, description)), action && (React.createElement("div", { className: "mt-4" }, React.createElement(Button, { variant: "primary", size: size === 'lg' ? 'md' : 'sm', onClick: action.onClick }, action.label))))); }; var ErrorState = function (_a) { var _b = _a.title, title = _b === void 0 ? 'Đã xảy ra lỗi' : _b, _c = _a.message, message = _c === void 0 ? 'Có lỗi xảy ra khi tải dữ liệu. Vui lòng thử lại sau.' : _c, onRetry = _a.onRetry, onHelp = _a.onHelp, className = _a.className, icon = _a.icon; return (React.createElement("div", { className: classNames('bg-red-50 border border-red-100 rounded-lg p-4 text-center', className) }, icon ? (React.createElement("div", { className: "mx-auto text-red-500 mb-3" }, icon)) : (React.createElement("div", { className: "mx-auto w-12 h-12 text-red-500 mb-3" }, React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })))), React.createElement("h3", { className: "text-lg font-medium text-red-800" }, title), React.createElement("p", { className: "mt-1 text-sm text-red-700" }, message), React.createElement("div", { className: "mt-4 flex flex-col sm:flex-row justify-center space-y-2 sm:space-y-0 sm:space-x-2" }, onRetry && (React.createElement(Button, { onClick: onRetry, variant: "primary" }, "Th\u1EED l\u1EA1i")), onHelp && (React.createElement(Button, { onClick: onHelp, variant: "outline" }, "Tr\u1EE3 gi\u00FAp"))))); }; var FormField = function (_a) { var name = _a.name, children = _a.children, props = __rest(_a, ["name", "children"]); return children ? (React.createElement("div", { className: "mb-4" }, props.label && (React.createElement("label", { htmlFor: name, className: "block mb-1 text-sm font-medium text-gray-700" }, props.label, props.required && React.createElement("span", { className: "text-red-500 ml-1" }, "*"))), children, props.error && (React.createElement("p", { className: "mt-1 text-sm text-red-500" }, props.error)), props.helperText && !props.error && (React.createElement("p", { className: "mt-1 text-sm text-gray-500" }, props.helperText)))) : (React.createElement(Input, __assign({ name: name, className: "mb-4" }, props))); }; var severityIconMap = { info: 'info', success: 'success', warning: 'warning', error: 'error', }; var Alert = function (_a) { var _b = _a.severity, severity = _b === void 0 ? 'info' : _b, _c = _a.variant, variant = _c === void 0 ? 'standard' : _c, title = _a.title, children = _a.children, className = _a.className, _d = _a.icon, icon = _d === void 0 ? true : _d, onClose = _a.onClose; // Cấu hình màu sắc dựa trên severity và variant var getColorClasses = function () { switch (variant) { case 'filled': return { info: 'bg-info-600 text-white', success: 'bg-success-600 text-white', warning: 'bg-warning-600 text-white', error: 'bg-error-600 text-white', }[severity]; case 'outlined': return { info: 'border border-info-300 bg-info-50 text-info-800', success: 'border border-success-300 bg-success-50 text-success-800', warning: 'border border-warning-300 bg-warning-50 text-warning-800', error: 'border border-error-300 bg-error-50 text-error-800', }[severity]; case 'standard': default: return { info: 'bg-info-50 text-info-800', success: 'bg-success-50 text-success-800', warning: 'bg-warning-50 text-warning-800', error: 'bg-error-50 text-error-800', }[severity]; } }; // Lấy màu biểu tượng var getIconColor = function () { if (variant === 'filled') return 'white'; return { info: 'info-600', success: 'success-600', warning: 'warning-600', error: 'error-600', }[severity]; }; // Render biểu tượng var renderIcon = function () { if (icon === false) return null; if (icon === true) { return (React.createElement("div", { className: "flex-shrink-0" }, React.createElement(Icon, { name: severityIconMap[severity], color: getIconColor(), size: "md" }))); } return React.createElement("div", { className: "flex-shrink-0" }, icon); }; return (React.createElement("div", { className: classNames('rounded-md p-4 flex', getColorClasses(), className), role: "alert" }, renderIcon(), React.createElement("div", { className: "ml-3 flex-grow" }, title && (React.createElement("h3", { className: classNames('text-sm font-medium', variant === 'filled' ? 'text-white' : '') }, title)), React.createElement("div", { className: classNames('text-sm', title ? 'mt-2' : '', variant === 'filled' ? 'text-white' : '') }, children)), onClose && (React.createElement("button", { type: "button", className: classNames('ml-auto -mx-1.5 -my-1.5 p-1.5 rounded-md focus:outline-none focus:ring-2', variant === 'filled' ? 'text-white hover:bg-opacity-10 hover:bg-white focus:ring-white' : "text-".concat(severity, "-600 hover:bg-").concat(severity, "-100 focus:ring-").concat(severity, "-500")), onClick: onClose, "aria-label": "\u0110\u00F3ng" }, React.createElement("span", { className: "sr-only" }, "\u0110\u00F3ng"), React.createElement(Icon, { name: "x", size: "sm" }))))); }; function DataTable(_a) { var columns = _a.columns, _b = _a.data, data = _b === void 0 ? [] : _b, keyExtractor = _a.keyExtractor, _c = _a.isLoading, isLoading = _c === void 0 ? false : _c, _d = _a.error, error = _d === void 0 ? null : _d, onRetry = _a.onRetry, _e = _a.emptyStateProps, emptyStateProps = _e === void 0 ? { title: 'Không có dữ liệu', description: 'Hiện không có dữ liệu nào. Vui lòng thử lại sau hoặc thêm dữ liệu mới.' } : _e, className = _a.className, rowClassName = _a.rowClassName; var renderSkeletonRows = function () { return Array(5) .fill(0) .map(function (_, index) { return (React.createElement("tr", { key: "skeleton-".concat(index), className: "animate-pulse" }, columns.map(function (column) { return (React.createElement("td", { key: "skeleton-cell-".concat(column.key, "-").concat(index), className: "px-4 py-3 border-b border-gray-200" }, React.createElement(Skeleton, { height: 20, width: "80%" }))); }))); }); }; var getRowClassName = function (item, index) { if (typeof rowClassName === 'function') { return rowClassName(item, index); } return rowClassName || ''; }; if (error) { return (React.createElement("div", { className: "border border-gray-200 rounded-lg overflow-hidden" }, React.createElement(ErrorState, { title: "Kh\u00F4ng th\u1EC3 t\u1EA3i d\u1EEF li\u1EC7u", message: error.message || 'Đã xảy ra lỗi khi tải dữ liệu. Vui lòng thử lại.', onRetry: onRetry }))); } if (!isLoading && (!data || data.length === 0)) { return (React.createElement("div", { className: "border border-gray-200 rounded-lg overflow-hidden" }, React.createElement(EmptyState, __assign({}, emptyStateProps)))); } return (React.createElement("div", { className: classNames('overflow-x-auto rounded-lg border border-gray-200', className) }, React.createElement("table", { className: "min-w-full divide-y divide-gray-200" }, React.createElement("thead", { className: "bg-gray-50" }, React.createElement("tr", null, columns.map(function (column) { return (React.createElement("th", { key: "header-".concat(column.key), className: "px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", style: { width: column.width } }, column.header)); }))), React.createElement("tbody", { className: "bg-white divide-y divide-gray-200" }, isLoading ? renderSkeletonRows() : data.map(function (item, index) { return (React.createElement("tr", { key: keyExtractor(item), className: classNames('hover:bg-gray-50', getRowClassName(item, index)) }, columns.map(function (column) { return (React.createElement("td", { key: "".concat(keyExtractor(item), "-").concat(column.key), className: "px-4 py-3 border-b border-gray-200" }, column.render ? column.render(item, index) : String(item[column.key]))); }))); }))))); } var Form = function (_a) { var children = _a.children, onSubmit = _a.onSubmit, _b = _a.isLoading, isLoading = _b === void 0 ? false : _b, _c = _a.submitLabel, submitLabel = _c === void 0 ? 'Lưu' : _c, _d = _a.resetLabel, resetLabel = _d === void 0 ? 'Huỷ' : _d, onReset = _a.onReset, error = _a.error, success = _a.success, actionButtons = _a.actionButtons, _e = _a.alignActions, alignActions = _e === void 0 ? 'right' : _e, className = _a.className, rest = __rest(_a, ["children", "onSubmit", "isLoading", "submitLabel", "resetLabel", "onReset", "error", "success", "actionButtons", "alignActions", "className"]); var handleSubmit = function (e) { e.preventDefault(); onSubmit(e); }; var alignmentClasses = { left: 'justify-start', center: 'justify-center', right: 'justify-end', }; return (React.createElement("form", __assign({ className: classNames('w-full', className), onSubmit: handleSubmit }, rest), React.createElement("div", { className: "space-y-4" }, children, error && (React.createElement("div", { className: "p-3 bg-red-50 border border-red-100 rounded text-red-700 text-sm" }, error)), success && (React.createElement("div", { className: "p-3 bg-green-50 border border-green-100 rounded text-green-700 text-sm" }, success)), React.createElement("div", { className: classNames('flex flex-wrap gap-3 pt-2', alignmentClasses[alignActions]) }, actionButtons || (React.createElement(React.Fragment, null, React.createElement(Button, { type: "submit", isLoading: isLoading, disabled: isLoading }, submitLabel), onReset && (React.createElement(Button, { type: "button", variant: "outline", onClick: onReset, disabled: isLoading }, resetLabel)))))))); }; // Fluid Responsive Design Utilities using Viewport-based Tailwind CSS // Thay đổi từ pixel cố định sang responsive theo tỉ lệ viewport // Viewport-based breakpoint values (rem units scale with root font-size) var FLUID_BREAKPOINTS = { xs: '20rem', // ~320px equivalent, scales with font-size sm: '30rem', // ~480px equivalent, scales with font-size md: '48rem', // ~768px equivalent, scales with font-size lg: '64rem', // ~1024px equivalent, scales with font-size xl: '80rem', // ~1280px equivalent, scales with font-size '2xl': '96rem', // ~1536px equivalent, scales with font-size '3xl': '120rem', // ~1920px equivalent, scales with font-size }; // Legacy pixel breakpoints (để compatibility với code cũ) var TAILWIND_BREAKPOINTS = { xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280, '2xl': 1536, }; // ======================================== // FLUID GRID UTILITIES (Grid tự động scale) // ======================================== var createFluidGrid = function (config) { var _a = config.type, type = _a === void 0 ? 'auto-fit' : _a, _b = config.minSize, minSize = _b === void 0 ? 'md' : _b, maxCols = config.maxCols, _c = config.gap, gap = _c === void 0 ? 'md' : _c, _d = config.aspectRatio, aspectRatio = _d === void 0 ? 'auto' : _d; var gapClasses = { xs: 'gap-fluid-xs', sm: 'gap-fluid-sm', base: 'gap-fluid-md', md: 'gap-fluid-md', lg: 'gap-fluid-lg', xl: 'gap-fluid-xl', '2xl': 'gap-fluid-2xl', '3xl': 'gap-fluid-3xl', }; var minSizeMap = { xs: '15rem', // ~240px sm: '18rem', // ~288px base: '20rem', // ~320px (same as md) md: '20rem', // ~320px lg: '25rem', // ~400px xl: '30rem', // ~480px '2xl': '35rem', // ~560px '3xl': '40rem', // ~640px }; var classes = ['grid']; // Grid template if (type === 'fixed' && maxCols) { classes.push("grid-cols-1 sm:grid-cols-2 md:grid-cols-".concat(Math.min(maxCols, 3), " lg:grid-cols-").concat(maxCols)); } else { var minSizeValue = typeof minSize === 'string' && minSize in minSizeMap ? minSizeMap[minSize] : minSize; classes.push("grid-cols-[repeat(".concat(type, ",minmax(min(100%,").concat(minSizeValue, "),1fr))]")); } // Gap classes.push(gapClasses[gap]); // Aspect ratio if (aspectRatio !== 'auto') { var aspectClasses = { square: '[&>*]:aspect-square', video: '[&>*]:aspect-video', photo: '[&>*]:aspect-[4/3]', }; classes.push(aspectClasses[aspectRatio]); } return classes.join(' '); }; // ======================================== // FLUID TYPOGRAPHY UTILITIES // ======================================== var createFluidText = function (config) { var _a = config.size, size = _a === void 0 ? 'base' : _a, weight = config.weight, _b = config.responsive, responsive = _b === void 0 ? true : _b; var classes = []; // Sử dụng fluid font sizes if (responsive) { var fluidSizes = { xs: 'text-fluid-xs', sm: 'text-fluid-sm', base: 'text-fluid-base', md: 'text-fluid-base', lg: 'text-fluid-lg', xl: 'text-fluid-xl', '2xl': 'text-fluid-2xl', '3xl': 'text-fluid-3xl', }; classes.push(fluidSizes[size] || fluidSizes.base); } else { classes.push("text-".concat(size)); } if (weight) { classes.push("font-".concat(weight)); } return classes.join(' '); }; // Display typography cho hero sections var createDisplayText = function (config) { var _a = config.size, size = _a === void 0 ? 'md' : _a, _b = config.weight, weight = _b === void 0 ? 'bold' : _b; var displaySizes = { sm: 'text-display-sm', md: 'text-display-md', lg: 'text-display-lg', xl: 'text-display-xl', }; return "".concat(displaySizes[size], " font-").concat(weight, " leading-tight tracking-tight"); }; // ======================================== // FLUID SPACING UTILITIES // ======================================== var createFluidSpacing = function (config) { var _a = config.size, size = _a === void 0 ? 'md' : _a, _b = config.type, type = _b === void 0 ? 'p' : _b, _c = config.context, context = _c === void 0 ? 'element' : _c; var contextMap = { element: { xs: 'fluid-xs', sm: 'fluid-sm', base: 'fluid-md', md: 'fluid-md', lg: 'fluid-lg', xl: 'fluid-xl', '2xl': 'fluid-2xl', '3xl': 'fluid-3xl' }, container: { xs: 'container-xs', sm: 'container-sm', base: 'container-sm', md: 'container-sm', lg: 'container-lg', xl: 'container-lg', '2xl': 'container-lg', '3xl': 'container-lg' }, section: { xs: 'section-xs', sm: 'section-xs', base: 'section-sm', md: 'section-sm', lg: 'section-sm', xl: 'section-lg', '2xl': 'section-lg', '3xl': 'section-lg' } }; var spacingValue = contextMap[context][size]; return "".concat(type, "-").concat(spacingValue); }; // ======================================== // FLUID CONTAINER UTILITIES // ======================================== var createFluidContainer = function (config) { var _a = config || {}, _b = _a.maxWidth, maxWidth = _b === void 0 ? 'fluid' : _b, _c = _a.padding, padding = _c === void 0 ? true : _c, _d = _a.center, center = _d === void 0 ? true : _d; var classes = []; if (center) { classes.push('mx-auto'); } // Fluid container với clamp if (maxWidth === 'fluid') { classes.push('w-full max-w-[clamp(20rem,90vw,100rem)]'); // 320px - 1600px } else if (maxWidth !== 'full') { classes.push("max-w-".concat(maxWidth)); } else { classes.push('w-full'); } if (padding) { classes.push('px-container-xs md:px-container-sm lg:px-container-lg'); } return classes.join(' '); }; // ======================================== // FLUID CARD UTILITIES // ======================================== var createFluidCard = function (config) { var _a = config || {}, _b = _a.padding, padding = _b === void 0 ? 'md' : _b, _c = _a.shadow, shadow = _c === void 0 ? 'md' : _c, _d = _a.rounded, rounded = _d === void 0 ? 'lg' : _d, _e = _a.border, border = _e === void 0 ? false : _e, _f = _a.hover, hover = _f === void 0 ? true : _f; var classes = [ 'bg-white', createFluidSpacing({ size: padding, type: 'p' }), "shadow-".concat(shadow), "rounded-".concat(rounded), ]; if (border) { classes.push('border border-gray-200'); } if (hover) { classes.push('transition-all duration-300 hover:shadow-lg hover:scale-[1.02]'); } return classes.join(' '); }; // ======================================== // VIEWPORT RESPONSIVE UTILITIES // ======================================== var createViewportGrid = function (config) { var _a = config.minWidth, minWidth = _a === void 0 ? '25vw' : _a; config.maxCols; var _c = config.gap, gap = _c === void 0 ? 'md' : _c; return createFluidGrid({ type: 'auto-fit', minSize: minWidth, gap: gap, }); }; // Responsive theo aspect ratio màn hình var createAspectRatioResponsive = function (config) { var widescreen = config.widescreen, standard = config.standard, mobile = config.mobile; var classes = []; if (mobile) { classes.push(mobile); } if (standard) { classes.push("portrait-tall:".concat(mobile || '', " landscape:").concat(standard)); } if (widescreen) { classes.push("landscape-wide:".concat(widescreen)); } return classes.join(' '); }; // ======================================== // FLUID PRESETS (Các bộ class có sẵn) // ======================================== var fluidPresets = { // Container presets container: { narrow: createFluidContainer({ maxWidth: 'lg' }), default: createFluidContainer(), wide: createFluidContainer({ maxWidth: '2xl' }), fullwidth: createFluidContainer({ maxWidth: 'full', padding: false }), fluid: createFluidContainer({ maxWidth: 'fluid' }), }, // Typography presets typography: { // Display text cho hero hero: createDisplayText({ size: 'xl', weight: 'bold' }), title: createDisplayText({ size: 'lg', weight: 'bold' }), subtitle: createDisplayText({ size: 'md', weight: 'bold' }), // Body text heading: createFluidText({ size: '2xl', weight: 'bold' }), subheading: createFluidText({ size: 'xl', weight: 'semibold' }), body: createFluidText({ size: 'base' }), caption: createFluidText({ size: 'sm' }), small: createFluidText({ size: 'xs' }), }, // Grid presets grid: { // Cards với auto-fit cards: createFluidGrid({ type: 'auto-fit', minSize: 'lg', gap: 'md' }), products: createFluidGrid({ type: 'auto-fit', minSize: 'md', gap: 'sm' }), gallery: createFluidGrid({ type: 'auto-fit', minSize: 'sm', gap: 'xs', aspectRatio: 'square' }), // Viewport-based grids 'viewport-cards': createViewportGrid({ minWidth: '25vw', gap: 'lg' }), 'viewport-products': createViewportGrid({ minWidth: '20vw', gap: 'md' }), 'viewport-gallery': createViewportGrid({ minWidth: '15vw', gap: 'sm' }), }, // Spacing presets spacing: { section: createFluidSpacing({ size: 'lg', type: 'py', context: 'section' }), container: createFluidSpacing({ size: 'md', type: 'px', context: 'container' }), element: createFluidSpacing({ size: 'md', type: 'p', context: 'element' }), // Margin presets sectionMargin: createFluidSpacing({ size: 'xl', type: 'mb', context: 'section' }), elementMargin: createFluidSpacing({ size: 'md', type: 'mb', context: 'element' }), }, // Card presets card: { default: createFluidCard(), compact: createFluidCard({ padding: 'sm' }), spacious: createFluidCard({ padding: 'lg' }), minimal: createFluidCard({ shadow: 'sm', border: true, hover: false }), }, }; // ======================================== // UTILITY FUNCTIONS // ======================================== var viewportUtils = { // Check viewport width (client-side only) getViewportWidth: function () { if (typeof window === 'undefined') return 1024; return window.innerWidth; }, // Check viewport height (client-side only) getViewportHeight: function () { if (typeof window === 'undefined') return 768; return window.innerHeight; }, // Get viewport aspect ratio getAspectRatio: function () { if (typeof window === 'undefined') return 16 / 9; return window.innerWidth / window.innerHeight; }, // Check if viewport is wide (≥16:9) isWidescreen: function () { return viewportUtils.getAspectRatio() >= 16 / 9; }, // Get device type based on viewport getDeviceType: function () { var width = viewportUtils.getViewportWidth(); if (width < 768) return 'mobile'; if (width < 1024) return 'tablet'; return 'desktop'; }, // Generate media query string mediaQuery: function (breakpoint) { return "@media (min-width: ".concat(FLUID_BREAKPOINTS[breakpoint], ")"); }, }; // ======================================== // BACKWARD COMPATIBILITY (Giữ lại cho code cũ) // ===============================