@frontmcp/ui 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -188
- package/bridge/adapters/claude.adapter.d.ts.map +1 -1
- package/bridge/adapters/gemini.adapter.d.ts.map +1 -1
- package/bridge/index.js +16 -4
- package/components/alert.d.ts +20 -3
- package/components/alert.d.ts.map +1 -1
- package/components/badge.d.ts +16 -2
- package/components/badge.d.ts.map +1 -1
- package/components/card.d.ts +29 -6
- package/components/card.d.ts.map +1 -1
- package/components/form.d.ts +21 -6
- package/components/form.d.ts.map +1 -1
- package/components/index.js +83 -30
- package/esm/bridge/index.mjs +16 -4
- package/esm/components/index.mjs +83 -30
- package/esm/index.mjs +94 -31
- package/esm/package.json +2 -2
- package/esm/renderers/index.mjs +11 -1
- package/esm/universal/index.mjs +2 -7
- package/esm/web-components/index.mjs +52 -22
- package/index.js +94 -31
- package/package.json +2 -2
- package/renderers/index.js +11 -1
- package/renderers/react.adapter.d.ts.map +1 -1
- package/universal/index.js +4 -9
- package/universal/renderers/html.renderer.d.ts +7 -8
- package/universal/renderers/html.renderer.d.ts.map +1 -1
- package/web-components/index.js +52 -22
package/index.js
CHANGED
|
@@ -1219,6 +1219,7 @@ var dangerButton = (text, opts) => button(text, { ...opts, variant: "danger" });
|
|
|
1219
1219
|
var linkButton = (text, opts) => button(text, { ...opts, variant: "link" });
|
|
1220
1220
|
|
|
1221
1221
|
// libs/ui/src/components/card.ts
|
|
1222
|
+
var import_runtime = require("@frontmcp/uipack/runtime");
|
|
1222
1223
|
function getVariantClasses2(variant) {
|
|
1223
1224
|
const variants = {
|
|
1224
1225
|
default: "bg-white border border-border rounded-xl shadow-sm",
|
|
@@ -1253,33 +1254,38 @@ function card(content, options = {}) {
|
|
|
1253
1254
|
id,
|
|
1254
1255
|
data,
|
|
1255
1256
|
clickable = false,
|
|
1256
|
-
href
|
|
1257
|
+
href,
|
|
1258
|
+
sanitize = false
|
|
1257
1259
|
} = options;
|
|
1260
|
+
const safeContent = sanitize ? (0, import_runtime.sanitizeHtmlContent)(content) : content;
|
|
1261
|
+
const safeHeaderActions = sanitize && headerActions ? (0, import_runtime.sanitizeHtmlContent)(headerActions) : headerActions;
|
|
1262
|
+
const safeFooter = sanitize && footer ? (0, import_runtime.sanitizeHtmlContent)(footer) : footer;
|
|
1258
1263
|
const variantClasses = getVariantClasses2(variant);
|
|
1259
1264
|
const sizeClasses = getSizeClasses2(size);
|
|
1260
1265
|
const clickableClasses = clickable ? "cursor-pointer hover:shadow-md transition-shadow" : "";
|
|
1261
|
-
const
|
|
1266
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1267
|
+
const allClasses = [variantClasses, sizeClasses, clickableClasses, safeClassName].filter(Boolean).join(" ");
|
|
1262
1268
|
const dataAttrs = buildDataAttrs(data);
|
|
1263
1269
|
const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
|
|
1264
|
-
const hasHeader = title || subtitle ||
|
|
1270
|
+
const hasHeader = title || subtitle || safeHeaderActions;
|
|
1265
1271
|
const headerHtml = hasHeader ? `<div class="flex items-start justify-between mb-4">
|
|
1266
1272
|
<div>
|
|
1267
1273
|
${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : ""}
|
|
1268
1274
|
${subtitle ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(subtitle)}</p>` : ""}
|
|
1269
1275
|
</div>
|
|
1270
|
-
${
|
|
1276
|
+
${safeHeaderActions ? `<div class="flex items-center gap-2">${safeHeaderActions}</div>` : ""}
|
|
1271
1277
|
</div>` : "";
|
|
1272
|
-
const footerHtml =
|
|
1278
|
+
const footerHtml = safeFooter ? `<div class="mt-4 pt-4 border-t border-divider">${safeFooter}</div>` : "";
|
|
1273
1279
|
if (href) {
|
|
1274
1280
|
return `<a href="${(0, import_utils2.escapeHtml)(href)}" class="${allClasses}" ${idAttr} ${dataAttrs}>
|
|
1275
1281
|
${headerHtml}
|
|
1276
|
-
${
|
|
1282
|
+
${safeContent}
|
|
1277
1283
|
${footerHtml}
|
|
1278
1284
|
</a>`;
|
|
1279
1285
|
}
|
|
1280
1286
|
return `<div class="${allClasses}" ${idAttr} ${dataAttrs}>
|
|
1281
1287
|
${headerHtml}
|
|
1282
|
-
${
|
|
1288
|
+
${safeContent}
|
|
1283
1289
|
${footerHtml}
|
|
1284
1290
|
</div>`;
|
|
1285
1291
|
}
|
|
@@ -1287,12 +1293,14 @@ function cardGroup(cards, options = {}) {
|
|
|
1287
1293
|
const { direction = "vertical", gap = "md", className = "" } = options;
|
|
1288
1294
|
const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
|
|
1289
1295
|
const directionClasses = direction === "horizontal" ? "flex flex-row flex-wrap" : "flex flex-col";
|
|
1290
|
-
|
|
1296
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1297
|
+
return `<div class="${directionClasses} ${gapClasses[gap]} ${safeClassName}">
|
|
1291
1298
|
${cards.join("\n")}
|
|
1292
1299
|
</div>`;
|
|
1293
1300
|
}
|
|
1294
1301
|
|
|
1295
1302
|
// libs/ui/src/components/form.ts
|
|
1303
|
+
var import_runtime2 = require("@frontmcp/uipack/runtime");
|
|
1296
1304
|
function getInputSizeClasses(size) {
|
|
1297
1305
|
const sizes = {
|
|
1298
1306
|
sm: "px-3 py-1.5 text-sm",
|
|
@@ -1337,11 +1345,15 @@ function input(options) {
|
|
|
1337
1345
|
className = "",
|
|
1338
1346
|
data,
|
|
1339
1347
|
iconBefore,
|
|
1340
|
-
iconAfter
|
|
1348
|
+
iconAfter,
|
|
1349
|
+
sanitize = false
|
|
1341
1350
|
} = options;
|
|
1351
|
+
const safeIconBefore = sanitize && iconBefore ? (0, import_runtime2.sanitizeHtmlContent)(iconBefore) : iconBefore;
|
|
1352
|
+
const safeIconAfter = sanitize && iconAfter ? (0, import_runtime2.sanitizeHtmlContent)(iconAfter) : iconAfter;
|
|
1342
1353
|
const sizeClasses = getInputSizeClasses(size);
|
|
1343
1354
|
const stateClasses = getInputStateClasses(state);
|
|
1344
|
-
const hasIcon =
|
|
1355
|
+
const hasIcon = safeIconBefore || safeIconAfter;
|
|
1356
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1345
1357
|
const baseClasses = [
|
|
1346
1358
|
"w-full rounded-lg border bg-white",
|
|
1347
1359
|
"transition-colors duration-200",
|
|
@@ -1349,8 +1361,8 @@ function input(options) {
|
|
|
1349
1361
|
disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
|
|
1350
1362
|
sizeClasses,
|
|
1351
1363
|
stateClasses,
|
|
1352
|
-
hasIcon ? (
|
|
1353
|
-
|
|
1364
|
+
hasIcon ? (safeIconBefore ? "pl-10" : "") + (safeIconAfter ? " pr-10" : "") : "",
|
|
1365
|
+
safeClassName
|
|
1354
1366
|
].filter(Boolean).join(" ");
|
|
1355
1367
|
const dataAttrs = buildDataAttrs2(data);
|
|
1356
1368
|
const inputAttrs = [
|
|
@@ -1375,8 +1387,8 @@ function input(options) {
|
|
|
1375
1387
|
</label>` : "";
|
|
1376
1388
|
const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
|
|
1377
1389
|
const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
|
|
1378
|
-
const iconBeforeHtml =
|
|
1379
|
-
const iconAfterHtml =
|
|
1390
|
+
const iconBeforeHtml = safeIconBefore ? `<span class="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconBefore}</span>` : "";
|
|
1391
|
+
const iconAfterHtml = safeIconAfter ? `<span class="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconAfter}</span>` : "";
|
|
1380
1392
|
const inputHtml = hasIcon ? `<div class="relative">
|
|
1381
1393
|
${iconBeforeHtml}
|
|
1382
1394
|
<input ${inputAttrs}>
|
|
@@ -1408,6 +1420,7 @@ function select(options) {
|
|
|
1408
1420
|
} = options;
|
|
1409
1421
|
const sizeClasses = getInputSizeClasses(size);
|
|
1410
1422
|
const stateClasses = getInputStateClasses(state);
|
|
1423
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1411
1424
|
const baseClasses = [
|
|
1412
1425
|
"w-full rounded-lg border bg-white",
|
|
1413
1426
|
"transition-colors duration-200",
|
|
@@ -1415,7 +1428,7 @@ function select(options) {
|
|
|
1415
1428
|
disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
|
|
1416
1429
|
sizeClasses,
|
|
1417
1430
|
stateClasses,
|
|
1418
|
-
|
|
1431
|
+
safeClassName
|
|
1419
1432
|
].filter(Boolean).join(" ");
|
|
1420
1433
|
const dataAttrs = buildDataAttrs2(data);
|
|
1421
1434
|
const optionsHtml = selectOptions.map((opt) => {
|
|
@@ -1472,6 +1485,7 @@ function textarea(options) {
|
|
|
1472
1485
|
horizontal: "resize-x",
|
|
1473
1486
|
both: "resize"
|
|
1474
1487
|
};
|
|
1488
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1475
1489
|
const baseClasses = [
|
|
1476
1490
|
"w-full rounded-lg border bg-white",
|
|
1477
1491
|
"transition-colors duration-200",
|
|
@@ -1480,7 +1494,7 @@ function textarea(options) {
|
|
|
1480
1494
|
sizeClasses,
|
|
1481
1495
|
stateClasses,
|
|
1482
1496
|
resizeClasses[resize],
|
|
1483
|
-
|
|
1497
|
+
safeClassName
|
|
1484
1498
|
].filter(Boolean).join(" ");
|
|
1485
1499
|
const dataAttrs = buildDataAttrs2(data);
|
|
1486
1500
|
const labelHtml = label ? `<label for="${(0, import_utils2.escapeHtml)(id)}" class="block text-sm font-medium text-text-primary mb-1.5">
|
|
@@ -1524,7 +1538,8 @@ function checkbox(options) {
|
|
|
1524
1538
|
].join(" ");
|
|
1525
1539
|
const helperHtml = helper && !error ? `<p class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
|
|
1526
1540
|
const errorHtml = error ? `<p class="text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
|
|
1527
|
-
|
|
1541
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1542
|
+
return `<div class="form-field ${safeClassName}">
|
|
1528
1543
|
<label class="flex items-start gap-3 ${disabled ? "cursor-not-allowed" : "cursor-pointer"}">
|
|
1529
1544
|
<input
|
|
1530
1545
|
type="checkbox"
|
|
@@ -1568,7 +1583,8 @@ function radioGroup(options) {
|
|
|
1568
1583
|
const labelHtml = label ? `<label class="block text-sm font-medium text-text-primary mb-2">${(0, import_utils2.escapeHtml)(label)}</label>` : "";
|
|
1569
1584
|
const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
|
|
1570
1585
|
const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
|
|
1571
|
-
|
|
1586
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1587
|
+
return `<div class="form-field ${safeClassName}" role="radiogroup">
|
|
1572
1588
|
${labelHtml}
|
|
1573
1589
|
<div class="${directionClasses}">
|
|
1574
1590
|
${radiosHtml}
|
|
@@ -1590,10 +1606,26 @@ function form(content, options = {}) {
|
|
|
1590
1606
|
].filter(Boolean).join(" ");
|
|
1591
1607
|
return `<form ${attrs}>${content}</form>`;
|
|
1592
1608
|
}
|
|
1609
|
+
var GRID_COLS_MAP = {
|
|
1610
|
+
1: "grid-cols-1",
|
|
1611
|
+
2: "grid-cols-2",
|
|
1612
|
+
3: "grid-cols-3",
|
|
1613
|
+
4: "grid-cols-4",
|
|
1614
|
+
5: "grid-cols-5",
|
|
1615
|
+
6: "grid-cols-6",
|
|
1616
|
+
7: "grid-cols-7",
|
|
1617
|
+
8: "grid-cols-8",
|
|
1618
|
+
9: "grid-cols-9",
|
|
1619
|
+
10: "grid-cols-10",
|
|
1620
|
+
11: "grid-cols-11",
|
|
1621
|
+
12: "grid-cols-12"
|
|
1622
|
+
};
|
|
1593
1623
|
function formRow(fields, options = {}) {
|
|
1594
1624
|
const { gap = "md", className = "" } = options;
|
|
1595
1625
|
const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
|
|
1596
|
-
|
|
1626
|
+
const gridCols = GRID_COLS_MAP[fields.length] ?? "grid-cols-1";
|
|
1627
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1628
|
+
return `<div class="grid ${gridCols} ${gapClasses[gap]} ${safeClassName}">
|
|
1597
1629
|
${fields.join("\n")}
|
|
1598
1630
|
</div>`;
|
|
1599
1631
|
}
|
|
@@ -1603,7 +1635,8 @@ function formSection(content, options = {}) {
|
|
|
1603
1635
|
<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>
|
|
1604
1636
|
${description ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(description)}</p>` : ""}
|
|
1605
1637
|
</div>` : "";
|
|
1606
|
-
|
|
1638
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1639
|
+
return `<div class="form-section ${safeClassName}">
|
|
1607
1640
|
${headerHtml}
|
|
1608
1641
|
<div class="space-y-4">
|
|
1609
1642
|
${content}
|
|
@@ -1618,7 +1651,8 @@ function formActions(buttons, options = {}) {
|
|
|
1618
1651
|
right: "justify-end",
|
|
1619
1652
|
between: "justify-between"
|
|
1620
1653
|
};
|
|
1621
|
-
|
|
1654
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1655
|
+
return `<div class="flex items-center gap-3 pt-4 ${alignClasses[align]} ${safeClassName}">
|
|
1622
1656
|
${buttons.join("\n")}
|
|
1623
1657
|
</div>`;
|
|
1624
1658
|
}
|
|
@@ -1630,6 +1664,7 @@ function csrfInput(token) {
|
|
|
1630
1664
|
}
|
|
1631
1665
|
|
|
1632
1666
|
// libs/ui/src/components/badge.ts
|
|
1667
|
+
var import_runtime3 = require("@frontmcp/uipack/runtime");
|
|
1633
1668
|
function getVariantClasses3(variant) {
|
|
1634
1669
|
const variants = {
|
|
1635
1670
|
default: "bg-gray-100 text-gray-800",
|
|
@@ -1667,8 +1702,11 @@ function badge(text, options = {}) {
|
|
|
1667
1702
|
icon,
|
|
1668
1703
|
dot = false,
|
|
1669
1704
|
className = "",
|
|
1670
|
-
removable = false
|
|
1705
|
+
removable = false,
|
|
1706
|
+
sanitize = false
|
|
1671
1707
|
} = options;
|
|
1708
|
+
const safeIcon = sanitize && icon ? (0, import_runtime3.sanitizeHtmlContent)(icon) : icon;
|
|
1709
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1672
1710
|
if (dot) {
|
|
1673
1711
|
const dotVariants = {
|
|
1674
1712
|
default: "bg-gray-400",
|
|
@@ -1680,7 +1718,7 @@ function badge(text, options = {}) {
|
|
|
1680
1718
|
info: "bg-blue-500",
|
|
1681
1719
|
outline: "border border-current"
|
|
1682
1720
|
};
|
|
1683
|
-
const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant],
|
|
1721
|
+
const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant], safeClassName].filter(Boolean).join(" ");
|
|
1684
1722
|
return `<span class="${dotClasses}" aria-label="${(0, import_utils2.escapeHtml)(text)}" title="${(0, import_utils2.escapeHtml)(text)}"></span>`;
|
|
1685
1723
|
}
|
|
1686
1724
|
const variantClasses = getVariantClasses3(variant);
|
|
@@ -1690,9 +1728,9 @@ function badge(text, options = {}) {
|
|
|
1690
1728
|
pill ? "rounded-full" : "rounded-md",
|
|
1691
1729
|
variantClasses,
|
|
1692
1730
|
sizeClasses,
|
|
1693
|
-
|
|
1731
|
+
safeClassName
|
|
1694
1732
|
].filter(Boolean).join(" ");
|
|
1695
|
-
const iconHtml =
|
|
1733
|
+
const iconHtml = safeIcon ? `<span class="mr-1">${safeIcon}</span>` : "";
|
|
1696
1734
|
const removeHtml = removable ? `<button
|
|
1697
1735
|
type="button"
|
|
1698
1736
|
class="ml-1.5 -mr-1 hover:opacity-70 transition-opacity"
|
|
@@ -1710,7 +1748,8 @@ function badge(text, options = {}) {
|
|
|
1710
1748
|
function badgeGroup(badges, options = {}) {
|
|
1711
1749
|
const { gap = "sm", className = "" } = options;
|
|
1712
1750
|
const gapClasses = { sm: "gap-1", md: "gap-2", lg: "gap-3" };
|
|
1713
|
-
|
|
1751
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1752
|
+
return `<div class="inline-flex flex-wrap ${gapClasses[gap]} ${safeClassName}">
|
|
1714
1753
|
${badges.join("\n")}
|
|
1715
1754
|
</div>`;
|
|
1716
1755
|
}
|
|
@@ -1726,6 +1765,7 @@ var busyDot = (label = "Busy") => badge(label, { variant: "danger", dot: true })
|
|
|
1726
1765
|
var awayDot = (label = "Away") => badge(label, { variant: "warning", dot: true });
|
|
1727
1766
|
|
|
1728
1767
|
// libs/ui/src/components/alert.ts
|
|
1768
|
+
var import_runtime4 = require("@frontmcp/uipack/runtime");
|
|
1729
1769
|
var alertIcons = {
|
|
1730
1770
|
info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1731
1771
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
@@ -1769,11 +1809,24 @@ function getVariantClasses4(variant) {
|
|
|
1769
1809
|
return variants[variant];
|
|
1770
1810
|
}
|
|
1771
1811
|
function alert(message, options = {}) {
|
|
1772
|
-
const {
|
|
1812
|
+
const {
|
|
1813
|
+
variant = "info",
|
|
1814
|
+
title,
|
|
1815
|
+
showIcon = true,
|
|
1816
|
+
icon,
|
|
1817
|
+
dismissible = false,
|
|
1818
|
+
className = "",
|
|
1819
|
+
id,
|
|
1820
|
+
actions,
|
|
1821
|
+
sanitize = false
|
|
1822
|
+
} = options;
|
|
1823
|
+
const safeIcon = sanitize && icon ? (0, import_runtime4.sanitizeHtmlContent)(icon) : icon;
|
|
1824
|
+
const safeActions = sanitize && actions ? (0, import_runtime4.sanitizeHtmlContent)(actions) : actions;
|
|
1773
1825
|
const variantClasses = getVariantClasses4(variant);
|
|
1774
|
-
const
|
|
1826
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1827
|
+
const baseClasses = ["rounded-lg border p-4", variantClasses.container, safeClassName].filter(Boolean).join(" ");
|
|
1775
1828
|
const iconHtml = showIcon ? `<div class="flex-shrink-0 ${variantClasses.icon}">
|
|
1776
|
-
${
|
|
1829
|
+
${safeIcon || alertIcons[variant]}
|
|
1777
1830
|
</div>` : "";
|
|
1778
1831
|
const titleHtml = title ? `<h3 class="font-semibold">${(0, import_utils2.escapeHtml)(title)}</h3>` : "";
|
|
1779
1832
|
const dismissHtml = dismissible ? `<button
|
|
@@ -1786,7 +1839,7 @@ function alert(message, options = {}) {
|
|
|
1786
1839
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
1787
1840
|
</svg>
|
|
1788
1841
|
</button>` : "";
|
|
1789
|
-
const actionsHtml =
|
|
1842
|
+
const actionsHtml = safeActions ? `<div class="mt-3">${safeActions}</div>` : "";
|
|
1790
1843
|
const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
|
|
1791
1844
|
return `<div class="alert ${baseClasses}" role="alert" ${idAttr}>
|
|
1792
1845
|
<div class="flex gap-3">
|
|
@@ -5258,7 +5311,17 @@ var ReactRendererAdapter = class {
|
|
|
5258
5311
|
return true;
|
|
5259
5312
|
}
|
|
5260
5313
|
if (typeof content === "string") {
|
|
5261
|
-
|
|
5314
|
+
if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
|
|
5315
|
+
return true;
|
|
5316
|
+
}
|
|
5317
|
+
const funcIndex = content.indexOf("function");
|
|
5318
|
+
if (funcIndex !== -1) {
|
|
5319
|
+
const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
|
|
5320
|
+
if (afterFunc.includes("return") && afterFunc.includes("<")) {
|
|
5321
|
+
return true;
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
return false;
|
|
5262
5325
|
}
|
|
5263
5326
|
return false;
|
|
5264
5327
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "FrontMCP UI - React components and hooks for MCP applications",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"react": "^18.0.0 || ^19.0.0",
|
|
66
66
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
67
|
-
"@frontmcp/uipack": "0.
|
|
67
|
+
"@frontmcp/uipack": "0.9.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/react": "^19.0.0",
|
package/renderers/index.js
CHANGED
|
@@ -250,7 +250,17 @@ var ReactRendererAdapter = class {
|
|
|
250
250
|
return true;
|
|
251
251
|
}
|
|
252
252
|
if (typeof content === "string") {
|
|
253
|
-
|
|
253
|
+
if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
const funcIndex = content.indexOf("function");
|
|
257
|
+
if (funcIndex !== -1) {
|
|
258
|
+
const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
|
|
259
|
+
if (afterFunc.includes("return") && afterFunc.includes("<")) {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
254
264
|
}
|
|
255
265
|
return false;
|
|
256
266
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.adapter.d.ts","sourceRoot":"","sources":["../../src/renderers/react.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC5G,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAsDrD;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAW;IAGhC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"react.adapter.d.ts","sourceRoot":"","sources":["../../src/renderers/react.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC5G,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAsDrD;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAW;IAGhC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO;IAiC7C;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMhG;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IA4DxB;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1G;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsChF;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAQlC;;OAEG;YACW,iBAAiB;IAa/B;;OAEG;YACW,SAAS;IAmCvB;;OAEG;IACH,OAAO,CAAC,YAAY;CAsBrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAEjE"}
|
package/universal/index.js
CHANGED
|
@@ -287,6 +287,8 @@ function withFrontMCP(Component) {
|
|
|
287
287
|
|
|
288
288
|
// libs/ui/src/universal/renderers/html.renderer.ts
|
|
289
289
|
var import_react3 = __toESM(require("react"));
|
|
290
|
+
var import_runtime = require("@frontmcp/uipack/runtime");
|
|
291
|
+
var sanitizeHtml = import_runtime.sanitizeHtmlContent;
|
|
290
292
|
var htmlRenderer = {
|
|
291
293
|
type: "html",
|
|
292
294
|
priority: 0,
|
|
@@ -305,13 +307,6 @@ var htmlRenderer = {
|
|
|
305
307
|
});
|
|
306
308
|
}
|
|
307
309
|
};
|
|
308
|
-
function sanitizeHtml(html) {
|
|
309
|
-
let sanitized = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
|
|
310
|
-
sanitized = sanitized.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, "");
|
|
311
|
-
sanitized = sanitized.replace(/\s+on\w+\s*=\s*[^\s>]*/gi, "");
|
|
312
|
-
sanitized = sanitized.replace(/href\s*=\s*["']javascript:[^"']*["']/gi, 'href="#"');
|
|
313
|
-
return sanitized;
|
|
314
|
-
}
|
|
315
310
|
var safeHtmlRenderer = {
|
|
316
311
|
type: "html",
|
|
317
312
|
priority: 0,
|
|
@@ -1177,7 +1172,7 @@ function buildMinimalRuntime(options) {
|
|
|
1177
1172
|
}
|
|
1178
1173
|
|
|
1179
1174
|
// libs/ui/src/universal/cached-runtime.ts
|
|
1180
|
-
var
|
|
1175
|
+
var import_runtime2 = require("@frontmcp/uipack/runtime");
|
|
1181
1176
|
var import_build = require("@frontmcp/uipack/build");
|
|
1182
1177
|
var RUNTIME_PLACEHOLDERS = {
|
|
1183
1178
|
/** Placeholder for transpiled component code */
|
|
@@ -1655,7 +1650,7 @@ function getCachedRuntime(options, config = {}) {
|
|
|
1655
1650
|
}
|
|
1656
1651
|
const vendorParts = [];
|
|
1657
1652
|
if (options.includeBridge) {
|
|
1658
|
-
vendorParts.push((0,
|
|
1653
|
+
vendorParts.push((0, import_runtime2.getMCPBridgeScript)());
|
|
1659
1654
|
}
|
|
1660
1655
|
vendorParts.push(buildStoreRuntime2(), buildRequireShim());
|
|
1661
1656
|
if (options.cdnType === "umd" || options.includeMarkdown) {
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
* Used for pre-rendered or server-side generated HTML content.
|
|
6
6
|
*/
|
|
7
7
|
import type { ClientRenderer } from '../types';
|
|
8
|
+
import { sanitizeHtmlContent } from '@frontmcp/uipack/runtime';
|
|
9
|
+
/**
|
|
10
|
+
* Re-export sanitizeHtmlContent as sanitizeHtml for backward compatibility.
|
|
11
|
+
* Uses DOMPurify in browser environments for robust sanitization.
|
|
12
|
+
*/
|
|
13
|
+
export declare const sanitizeHtml: typeof sanitizeHtmlContent;
|
|
8
14
|
/**
|
|
9
15
|
* HTML renderer implementation.
|
|
10
16
|
*
|
|
@@ -22,16 +28,9 @@ import type { ClientRenderer } from '../types';
|
|
|
22
28
|
* ```
|
|
23
29
|
*/
|
|
24
30
|
export declare const htmlRenderer: ClientRenderer;
|
|
25
|
-
/**
|
|
26
|
-
* Sanitize HTML string (basic XSS protection).
|
|
27
|
-
* For production use, consider using a library like DOMPurify.
|
|
28
|
-
*
|
|
29
|
-
* @param html - HTML string to sanitize
|
|
30
|
-
* @returns Sanitized HTML string
|
|
31
|
-
*/
|
|
32
|
-
export declare function sanitizeHtml(html: string): string;
|
|
33
31
|
/**
|
|
34
32
|
* Create a safe HTML renderer that sanitizes content.
|
|
33
|
+
* Uses DOMPurify in browser environments for robust protection against XSS.
|
|
35
34
|
*/
|
|
36
35
|
export declare const safeHtmlRenderer: ClientRenderer;
|
|
37
36
|
//# sourceMappingURL=html.renderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.renderer.d.ts","sourceRoot":"","sources":["../../../src/universal/renderers/html.renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"html.renderer.d.ts","sourceRoot":"","sources":["../../../src/universal/renderers/html.renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,YAAY,4BAAsB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,cAsB1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAsB9B,CAAC"}
|
package/web-components/index.js
CHANGED
|
@@ -652,6 +652,7 @@ function registerFmcpButton() {
|
|
|
652
652
|
}
|
|
653
653
|
|
|
654
654
|
// libs/ui/src/components/card.ts
|
|
655
|
+
var import_runtime = require("@frontmcp/uipack/runtime");
|
|
655
656
|
function getVariantClasses2(variant) {
|
|
656
657
|
const variants = {
|
|
657
658
|
default: "bg-white border border-border rounded-xl shadow-sm",
|
|
@@ -686,33 +687,38 @@ function card(content, options = {}) {
|
|
|
686
687
|
id,
|
|
687
688
|
data,
|
|
688
689
|
clickable = false,
|
|
689
|
-
href
|
|
690
|
+
href,
|
|
691
|
+
sanitize = false
|
|
690
692
|
} = options;
|
|
693
|
+
const safeContent = sanitize ? (0, import_runtime.sanitizeHtmlContent)(content) : content;
|
|
694
|
+
const safeHeaderActions = sanitize && headerActions ? (0, import_runtime.sanitizeHtmlContent)(headerActions) : headerActions;
|
|
695
|
+
const safeFooter = sanitize && footer ? (0, import_runtime.sanitizeHtmlContent)(footer) : footer;
|
|
691
696
|
const variantClasses = getVariantClasses2(variant);
|
|
692
697
|
const sizeClasses = getSizeClasses2(size);
|
|
693
698
|
const clickableClasses = clickable ? "cursor-pointer hover:shadow-md transition-shadow" : "";
|
|
694
|
-
const
|
|
699
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
700
|
+
const allClasses = [variantClasses, sizeClasses, clickableClasses, safeClassName].filter(Boolean).join(" ");
|
|
695
701
|
const dataAttrs = buildDataAttrs(data);
|
|
696
702
|
const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
|
|
697
|
-
const hasHeader = title || subtitle ||
|
|
703
|
+
const hasHeader = title || subtitle || safeHeaderActions;
|
|
698
704
|
const headerHtml = hasHeader ? `<div class="flex items-start justify-between mb-4">
|
|
699
705
|
<div>
|
|
700
706
|
${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : ""}
|
|
701
707
|
${subtitle ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(subtitle)}</p>` : ""}
|
|
702
708
|
</div>
|
|
703
|
-
${
|
|
709
|
+
${safeHeaderActions ? `<div class="flex items-center gap-2">${safeHeaderActions}</div>` : ""}
|
|
704
710
|
</div>` : "";
|
|
705
|
-
const footerHtml =
|
|
711
|
+
const footerHtml = safeFooter ? `<div class="mt-4 pt-4 border-t border-divider">${safeFooter}</div>` : "";
|
|
706
712
|
if (href) {
|
|
707
713
|
return `<a href="${(0, import_utils2.escapeHtml)(href)}" class="${allClasses}" ${idAttr} ${dataAttrs}>
|
|
708
714
|
${headerHtml}
|
|
709
|
-
${
|
|
715
|
+
${safeContent}
|
|
710
716
|
${footerHtml}
|
|
711
717
|
</a>`;
|
|
712
718
|
}
|
|
713
719
|
return `<div class="${allClasses}" ${idAttr} ${dataAttrs}>
|
|
714
720
|
${headerHtml}
|
|
715
|
-
${
|
|
721
|
+
${safeContent}
|
|
716
722
|
${footerHtml}
|
|
717
723
|
</div>`;
|
|
718
724
|
}
|
|
@@ -835,6 +841,7 @@ function registerFmcpCard() {
|
|
|
835
841
|
}
|
|
836
842
|
|
|
837
843
|
// libs/ui/src/components/alert.ts
|
|
844
|
+
var import_runtime2 = require("@frontmcp/uipack/runtime");
|
|
838
845
|
var alertIcons = {
|
|
839
846
|
info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
840
847
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
@@ -878,11 +885,24 @@ function getVariantClasses3(variant) {
|
|
|
878
885
|
return variants[variant];
|
|
879
886
|
}
|
|
880
887
|
function alert(message, options = {}) {
|
|
881
|
-
const {
|
|
888
|
+
const {
|
|
889
|
+
variant = "info",
|
|
890
|
+
title,
|
|
891
|
+
showIcon = true,
|
|
892
|
+
icon,
|
|
893
|
+
dismissible = false,
|
|
894
|
+
className = "",
|
|
895
|
+
id,
|
|
896
|
+
actions,
|
|
897
|
+
sanitize = false
|
|
898
|
+
} = options;
|
|
899
|
+
const safeIcon = sanitize && icon ? (0, import_runtime2.sanitizeHtmlContent)(icon) : icon;
|
|
900
|
+
const safeActions = sanitize && actions ? (0, import_runtime2.sanitizeHtmlContent)(actions) : actions;
|
|
882
901
|
const variantClasses = getVariantClasses3(variant);
|
|
883
|
-
const
|
|
902
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
903
|
+
const baseClasses = ["rounded-lg border p-4", variantClasses.container, safeClassName].filter(Boolean).join(" ");
|
|
884
904
|
const iconHtml = showIcon ? `<div class="flex-shrink-0 ${variantClasses.icon}">
|
|
885
|
-
${
|
|
905
|
+
${safeIcon || alertIcons[variant]}
|
|
886
906
|
</div>` : "";
|
|
887
907
|
const titleHtml = title ? `<h3 class="font-semibold">${(0, import_utils2.escapeHtml)(title)}</h3>` : "";
|
|
888
908
|
const dismissHtml = dismissible ? `<button
|
|
@@ -895,7 +915,7 @@ function alert(message, options = {}) {
|
|
|
895
915
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
896
916
|
</svg>
|
|
897
917
|
</button>` : "";
|
|
898
|
-
const actionsHtml =
|
|
918
|
+
const actionsHtml = safeActions ? `<div class="mt-3">${safeActions}</div>` : "";
|
|
899
919
|
const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
|
|
900
920
|
return `<div class="alert ${baseClasses}" role="alert" ${idAttr}>
|
|
901
921
|
<div class="flex gap-3">
|
|
@@ -1012,6 +1032,7 @@ function registerFmcpAlert() {
|
|
|
1012
1032
|
}
|
|
1013
1033
|
|
|
1014
1034
|
// libs/ui/src/components/badge.ts
|
|
1035
|
+
var import_runtime3 = require("@frontmcp/uipack/runtime");
|
|
1015
1036
|
function getVariantClasses4(variant) {
|
|
1016
1037
|
const variants = {
|
|
1017
1038
|
default: "bg-gray-100 text-gray-800",
|
|
@@ -1049,8 +1070,11 @@ function badge(text, options = {}) {
|
|
|
1049
1070
|
icon,
|
|
1050
1071
|
dot = false,
|
|
1051
1072
|
className = "",
|
|
1052
|
-
removable = false
|
|
1073
|
+
removable = false,
|
|
1074
|
+
sanitize = false
|
|
1053
1075
|
} = options;
|
|
1076
|
+
const safeIcon = sanitize && icon ? (0, import_runtime3.sanitizeHtmlContent)(icon) : icon;
|
|
1077
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1054
1078
|
if (dot) {
|
|
1055
1079
|
const dotVariants = {
|
|
1056
1080
|
default: "bg-gray-400",
|
|
@@ -1062,7 +1086,7 @@ function badge(text, options = {}) {
|
|
|
1062
1086
|
info: "bg-blue-500",
|
|
1063
1087
|
outline: "border border-current"
|
|
1064
1088
|
};
|
|
1065
|
-
const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant],
|
|
1089
|
+
const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant], safeClassName].filter(Boolean).join(" ");
|
|
1066
1090
|
return `<span class="${dotClasses}" aria-label="${(0, import_utils2.escapeHtml)(text)}" title="${(0, import_utils2.escapeHtml)(text)}"></span>`;
|
|
1067
1091
|
}
|
|
1068
1092
|
const variantClasses = getVariantClasses4(variant);
|
|
@@ -1072,9 +1096,9 @@ function badge(text, options = {}) {
|
|
|
1072
1096
|
pill ? "rounded-full" : "rounded-md",
|
|
1073
1097
|
variantClasses,
|
|
1074
1098
|
sizeClasses,
|
|
1075
|
-
|
|
1099
|
+
safeClassName
|
|
1076
1100
|
].filter(Boolean).join(" ");
|
|
1077
|
-
const iconHtml =
|
|
1101
|
+
const iconHtml = safeIcon ? `<span class="mr-1">${safeIcon}</span>` : "";
|
|
1078
1102
|
const removeHtml = removable ? `<button
|
|
1079
1103
|
type="button"
|
|
1080
1104
|
class="ml-1.5 -mr-1 hover:opacity-70 transition-opacity"
|
|
@@ -1193,6 +1217,7 @@ function registerFmcpBadge() {
|
|
|
1193
1217
|
}
|
|
1194
1218
|
|
|
1195
1219
|
// libs/ui/src/components/form.ts
|
|
1220
|
+
var import_runtime4 = require("@frontmcp/uipack/runtime");
|
|
1196
1221
|
function getInputSizeClasses(size) {
|
|
1197
1222
|
const sizes = {
|
|
1198
1223
|
sm: "px-3 py-1.5 text-sm",
|
|
@@ -1237,11 +1262,15 @@ function input(options) {
|
|
|
1237
1262
|
className = "",
|
|
1238
1263
|
data,
|
|
1239
1264
|
iconBefore,
|
|
1240
|
-
iconAfter
|
|
1265
|
+
iconAfter,
|
|
1266
|
+
sanitize = false
|
|
1241
1267
|
} = options;
|
|
1268
|
+
const safeIconBefore = sanitize && iconBefore ? (0, import_runtime4.sanitizeHtmlContent)(iconBefore) : iconBefore;
|
|
1269
|
+
const safeIconAfter = sanitize && iconAfter ? (0, import_runtime4.sanitizeHtmlContent)(iconAfter) : iconAfter;
|
|
1242
1270
|
const sizeClasses = getInputSizeClasses(size);
|
|
1243
1271
|
const stateClasses = getInputStateClasses(state);
|
|
1244
|
-
const hasIcon =
|
|
1272
|
+
const hasIcon = safeIconBefore || safeIconAfter;
|
|
1273
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1245
1274
|
const baseClasses = [
|
|
1246
1275
|
"w-full rounded-lg border bg-white",
|
|
1247
1276
|
"transition-colors duration-200",
|
|
@@ -1249,8 +1278,8 @@ function input(options) {
|
|
|
1249
1278
|
disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
|
|
1250
1279
|
sizeClasses,
|
|
1251
1280
|
stateClasses,
|
|
1252
|
-
hasIcon ? (
|
|
1253
|
-
|
|
1281
|
+
hasIcon ? (safeIconBefore ? "pl-10" : "") + (safeIconAfter ? " pr-10" : "") : "",
|
|
1282
|
+
safeClassName
|
|
1254
1283
|
].filter(Boolean).join(" ");
|
|
1255
1284
|
const dataAttrs = buildDataAttrs2(data);
|
|
1256
1285
|
const inputAttrs = [
|
|
@@ -1275,8 +1304,8 @@ function input(options) {
|
|
|
1275
1304
|
</label>` : "";
|
|
1276
1305
|
const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
|
|
1277
1306
|
const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
|
|
1278
|
-
const iconBeforeHtml =
|
|
1279
|
-
const iconAfterHtml =
|
|
1307
|
+
const iconBeforeHtml = safeIconBefore ? `<span class="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconBefore}</span>` : "";
|
|
1308
|
+
const iconAfterHtml = safeIconAfter ? `<span class="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconAfter}</span>` : "";
|
|
1280
1309
|
const inputHtml = hasIcon ? `<div class="relative">
|
|
1281
1310
|
${iconBeforeHtml}
|
|
1282
1311
|
<input ${inputAttrs}>
|
|
@@ -1308,6 +1337,7 @@ function select(options) {
|
|
|
1308
1337
|
} = options;
|
|
1309
1338
|
const sizeClasses = getInputSizeClasses(size);
|
|
1310
1339
|
const stateClasses = getInputStateClasses(state);
|
|
1340
|
+
const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
|
|
1311
1341
|
const baseClasses = [
|
|
1312
1342
|
"w-full rounded-lg border bg-white",
|
|
1313
1343
|
"transition-colors duration-200",
|
|
@@ -1315,7 +1345,7 @@ function select(options) {
|
|
|
1315
1345
|
disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
|
|
1316
1346
|
sizeClasses,
|
|
1317
1347
|
stateClasses,
|
|
1318
|
-
|
|
1348
|
+
safeClassName
|
|
1319
1349
|
].filter(Boolean).join(" ");
|
|
1320
1350
|
const dataAttrs = buildDataAttrs2(data);
|
|
1321
1351
|
const optionsHtml = selectOptions.map((opt) => {
|