@axzydev/axzy_ui_system 1.7.2 → 1.7.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.
Files changed (63) hide show
  1. package/dist/index.cjs +1630 -589
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.cts +373 -13
  5. package/dist/index.d.ts +373 -13
  6. package/dist/index.js +1346 -314
  7. package/dist/index.js.map +1 -1
  8. package/dist/layered.css +1 -1
  9. package/package.json +4 -2
  10. package/src/App.tsx +6 -8
  11. package/src/components/atoms/flex/flex.props.ts +3 -1
  12. package/src/components/atoms/flex/flex.tsx +11 -3
  13. package/src/components/atoms/textarea/textarea.props.ts +4 -0
  14. package/src/components/atoms/textarea/textarea.tsx +13 -3
  15. package/src/components/molecules/card/card.props.ts +2 -0
  16. package/src/components/molecules/card/card.tsx +15 -2
  17. package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +4 -0
  18. package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +57 -41
  19. package/src/components/molecules/stat-card/stat-card.props.ts +7 -0
  20. package/src/components/molecules/stat-card/stat-card.tsx +18 -0
  21. package/src/components/organisms/dropfile/dropfile.props.ts +8 -2
  22. package/src/components/organisms/dropfile/dropfile.tsx +17 -0
  23. package/src/i18n/locales/en.ts +7 -0
  24. package/src/i18n/locales/es.ts +7 -0
  25. package/src/index.ts +31 -3
  26. package/src/json-renderer/actions/effects.test.tsx +115 -0
  27. package/src/json-renderer/actions/effects.ts +291 -0
  28. package/src/json-renderer/actions/effectsChain.test.ts +117 -0
  29. package/src/json-renderer/binding/binding.test.tsx +168 -0
  30. package/src/json-renderer/binding/resolveValue.ts +193 -0
  31. package/src/json-renderer/estado-acciones.test.tsx +166 -0
  32. package/src/json-renderer/form/FormNode.tsx +92 -0
  33. package/src/json-renderer/form/form.test.tsx +148 -0
  34. package/src/json-renderer/form/formLength.test.tsx +99 -0
  35. package/src/json-renderer/form/rules.ts +162 -0
  36. package/src/json-renderer/index.ts +21 -0
  37. package/src/json-renderer/kernel/SchemaRenderer.tsx +83 -7
  38. package/src/json-renderer/kernel/capabilities.ts +30 -0
  39. package/src/json-renderer/kernel/renderNode.tsx +256 -3
  40. package/src/json-renderer/kernel/schemaRenderer.props.ts +29 -3
  41. package/src/json-renderer/kernel/slots.test.tsx +104 -0
  42. package/src/json-renderer/kernel/slots.ts +34 -0
  43. package/src/json-renderer/kernel/types.ts +4 -0
  44. package/src/json-renderer/routing/match.ts +82 -0
  45. package/src/json-renderer/routing/navigation.ts +71 -0
  46. package/src/json-renderer/routing/routes.ts +179 -0
  47. package/src/json-renderer/routing/routing.test.ts +147 -0
  48. package/src/json-renderer/seguridad.test.tsx +299 -0
  49. package/src/json-renderer/shared/errors.ts +1 -0
  50. package/src/json-renderer/stream/tolerantParse.ts +5 -0
  51. package/src/json-renderer/stream/useSchemaStream.test.tsx +143 -0
  52. package/src/json-renderer/stream/useSchemaStream.ts +227 -0
  53. package/src/json-renderer/validation/jsonSchema.test.ts +105 -0
  54. package/src/json-renderer/validation/jsonSchema.ts +317 -0
  55. package/src/json-renderer/validation/validate.ts +17 -0
  56. package/src/sandbox/i18n.ts +38 -0
  57. package/src/sandbox/useHashRoute.ts +2 -1
  58. package/src/showcases/DemoJsonDashboard.tsx +218 -103
  59. package/src/showcases/DemoJsonDocs.tsx +11 -11
  60. package/src/showcases/JsonScreenShowcase.tsx +43 -53
  61. package/src/showcases/demoApp/demoJson.test.tsx +241 -0
  62. package/src/showcases/demoApp/routes.test.ts +63 -0
  63. package/src/showcases/demoApp/schemas.test.ts +6 -17
package/dist/index.js CHANGED
@@ -1205,7 +1205,13 @@ var es = {
1205
1205
  "jsonEditor.kindString": "texto",
1206
1206
  "jsonEditor.kindNumber": "n\xFAmero",
1207
1207
  "jsonEditor.kindBoolean": "booleano",
1208
- "jsonEditor.kindNull": "nulo"
1208
+ "jsonEditor.kindNull": "nulo",
1209
+ // ---------------------------------------------------------------- jsonRenderer
1210
+ "jsonRenderer.form.required": "Campo obligatorio.",
1211
+ "jsonRenderer.form.email": "Escribe un correo v\xE1lido.",
1212
+ "jsonRenderer.form.minLength": "Escribe al menos {min} caracteres.",
1213
+ "jsonRenderer.form.maxLength": "Escribe como m\xE1ximo {max} caracteres.",
1214
+ "jsonRenderer.form.submit": "Enviar"
1209
1215
  };
1210
1216
  var es_default = es;
1211
1217
 
@@ -1411,7 +1417,13 @@ var en = {
1411
1417
  "jsonEditor.kindString": "string",
1412
1418
  "jsonEditor.kindNumber": "number",
1413
1419
  "jsonEditor.kindBoolean": "boolean",
1414
- "jsonEditor.kindNull": "null"
1420
+ "jsonEditor.kindNull": "null",
1421
+ // ---------------------------------------------------------------- jsonRenderer
1422
+ "jsonRenderer.form.required": "Required field.",
1423
+ "jsonRenderer.form.email": "Enter a valid email address.",
1424
+ "jsonRenderer.form.minLength": "Enter at least {min} characters.",
1425
+ "jsonRenderer.form.maxLength": "Enter at most {max} characters.",
1426
+ "jsonRenderer.form.submit": "Submit"
1415
1427
  };
1416
1428
  var en_default = en;
1417
1429
 
@@ -1488,6 +1500,7 @@ function useITTranslation() {
1488
1500
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1489
1501
  function ITCard({
1490
1502
  title,
1503
+ headerActions,
1491
1504
  image,
1492
1505
  alt,
1493
1506
  children,
@@ -1547,14 +1560,24 @@ function ITCard({
1547
1560
  }
1548
1561
  ),
1549
1562
  /* @__PURE__ */ jsxs2("div", { className: clsx2(contentClassName), style: bodyStyle, children: [
1550
- title && /* @__PURE__ */ jsx4(
1563
+ headerActions ? /* @__PURE__ */ jsxs2("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
1564
+ title && /* @__PURE__ */ jsx4(
1565
+ ITText,
1566
+ {
1567
+ as: "h3",
1568
+ className: clsx2(flat ? "text-base font-semibold" : "text-xl font-semibold", titleClassName),
1569
+ children: title
1570
+ }
1571
+ ),
1572
+ headerActions
1573
+ ] }) : title ? /* @__PURE__ */ jsx4(
1551
1574
  ITText,
1552
1575
  {
1553
1576
  as: "h3",
1554
1577
  className: clsx2(flat ? "text-base font-semibold mb-3" : "text-xl font-semibold mb-2", titleClassName),
1555
1578
  children: title
1556
1579
  }
1557
- ),
1580
+ ) : null,
1558
1581
  /* @__PURE__ */ jsx4(ITText, { as: "div", className: "text-secondary-600", children })
1559
1582
  ] }),
1560
1583
  actions && /* @__PURE__ */ jsx4(
@@ -1574,6 +1597,7 @@ function ITCard({
1574
1597
 
1575
1598
  // src/components/atoms/flex/flex.tsx
1576
1599
  import clsx3 from "clsx";
1600
+ import { forwardRef } from "react";
1577
1601
  import { jsx as jsx5 } from "react/jsx-runtime";
1578
1602
  var directionMap = {
1579
1603
  row: "flex-row",
@@ -1601,7 +1625,7 @@ var wrapMap = {
1601
1625
  wrap: "flex-wrap",
1602
1626
  "wrap-reverse": "flex-wrap-reverse"
1603
1627
  };
1604
- function ITFlex({
1628
+ var ITFlex = forwardRef(function ITFlex2({
1605
1629
  children,
1606
1630
  direction = "row",
1607
1631
  align,
@@ -1614,8 +1638,9 @@ function ITFlex({
1614
1638
  className,
1615
1639
  style,
1616
1640
  as: Component = "div",
1617
- onClick
1618
- }) {
1641
+ onClick,
1642
+ onScroll
1643
+ }, ref) {
1619
1644
  const resolvedStyle = {
1620
1645
  gap: gap > 0 ? `${gap * 0.25}rem` : void 0,
1621
1646
  flexGrow: typeof grow === "boolean" ? grow ? 1 : 0 : grow,
@@ -1626,6 +1651,7 @@ function ITFlex({
1626
1651
  return /* @__PURE__ */ jsx5(
1627
1652
  Component,
1628
1653
  {
1654
+ ref,
1629
1655
  className: clsx3(
1630
1656
  "flex",
1631
1657
  directionMap[direction],
@@ -1636,10 +1662,13 @@ function ITFlex({
1636
1662
  ),
1637
1663
  style: resolvedStyle,
1638
1664
  onClick,
1665
+ onScroll,
1639
1666
  children
1640
1667
  }
1641
1668
  );
1642
- }
1669
+ });
1670
+ ITFlex.displayName = "ITFlex";
1671
+ var flex_default = ITFlex;
1643
1672
 
1644
1673
  // src/components/atoms/stack/stack.tsx
1645
1674
  import clsx4 from "clsx";
@@ -1854,7 +1883,7 @@ function ITJsonRenderer({
1854
1883
  case "card":
1855
1884
  return /* @__PURE__ */ jsx9(ITCard, { ...props, children: childContent });
1856
1885
  case "flex":
1857
- return /* @__PURE__ */ jsx9(ITFlex, { ...props, children: childContent });
1886
+ return /* @__PURE__ */ jsx9(flex_default, { ...props, children: childContent });
1858
1887
  case "stack":
1859
1888
  return /* @__PURE__ */ jsx9(ITStack, { ...props, children: childContent });
1860
1889
  case "grid":
@@ -8935,6 +8964,9 @@ function ITStatCard({
8935
8964
  value,
8936
8965
  trend,
8937
8966
  trendDirection = trend && trend.startsWith("-") ? "down" : "neutral",
8967
+ hint,
8968
+ progress,
8969
+ progressColor = "primary",
8938
8970
  icon,
8939
8971
  color = "bg-primary-50 dark:bg-primary-950/20",
8940
8972
  className,
@@ -8963,7 +8995,18 @@ function ITStatCard({
8963
8995
  /* @__PURE__ */ jsxs44("div", { className: "flex items-baseline gap-2", children: [
8964
8996
  /* @__PURE__ */ jsx63(ITText, { as: "span", className: "text-2xl font-bold text-slate-800 dark:text-white", children: value }),
8965
8997
  trend && /* @__PURE__ */ jsx63(ITText, { as: "span", className: clsx44("text-[11px] font-semibold px-1.5 py-0.5 rounded-md", trendColors[trendDirection]), children: trend })
8966
- ] })
8998
+ ] }),
8999
+ hint && /* @__PURE__ */ jsx63(ITText, { as: "p", className: "mt-1 text-[11px] leading-snug text-slate-500 dark:text-slate-400", children: hint }),
9000
+ progress !== void 0 && /* @__PURE__ */ jsx63(
9001
+ ITProgress,
9002
+ {
9003
+ value: progress,
9004
+ max: 100,
9005
+ color: progressColor,
9006
+ size: "sm",
9007
+ className: "mt-2"
9008
+ }
9009
+ )
8967
9010
  ]
8968
9011
  }
8969
9012
  );
@@ -8979,6 +9022,8 @@ function ITLineBarChart({
8979
9022
  barLabel,
8980
9023
  lineColor = "#10b981",
8981
9024
  barColor = "#3b82f6",
9025
+ showLine = true,
9026
+ showBars = true,
8982
9027
  height = 240,
8983
9028
  formatValue,
8984
9029
  formatAxis,
@@ -8996,8 +9041,11 @@ function ITLineBarChart({
8996
9041
  const plotWidth = width - padding.left - padding.right;
8997
9042
  const plotHeight = height - padding.top - padding.bottom;
8998
9043
  const max = useMemo13(
8999
- () => Math.max(...data.flatMap((d) => [d.line, d.bar]), 1),
9000
- [data]
9044
+ () => Math.max(
9045
+ ...data.flatMap((d) => [showLine ? d.line : 0, showBars ? d.bar : 0]),
9046
+ 1
9047
+ ),
9048
+ [data, showLine, showBars]
9001
9049
  );
9002
9050
  const gridValues = [0, 0.25, 0.5, 0.75, 1].map((f) => max * f);
9003
9051
  const step = data.length > 0 ? plotWidth / data.length : plotWidth;
@@ -9041,7 +9089,7 @@ function ITLineBarChart({
9041
9089
  ),
9042
9090
  /* @__PURE__ */ jsx64("text", { x: padding.left - 8, y: y(value) + 3, textAnchor: "end", fontSize: 10, fill: "#94a3b8", children: resolvedFormatAxis(Math.round(value)) })
9043
9091
  ] }, i)),
9044
- data.map((d, i) => /* @__PURE__ */ jsx64(
9092
+ showBars && data.map((d, i) => /* @__PURE__ */ jsx64(
9045
9093
  "rect",
9046
9094
  {
9047
9095
  x: x(i) - barWidth / 2,
@@ -9054,8 +9102,8 @@ function ITLineBarChart({
9054
9102
  },
9055
9103
  `bar-${d.label}`
9056
9104
  )),
9057
- areaPath && /* @__PURE__ */ jsx64("path", { d: areaPath, fill: `url(#area-${gradientId})` }),
9058
- data.length > 0 && /* @__PURE__ */ jsx64(
9105
+ showLine && areaPath && /* @__PURE__ */ jsx64("path", { d: areaPath, fill: `url(#area-${gradientId})` }),
9106
+ showLine && data.length > 0 && /* @__PURE__ */ jsx64(
9059
9107
  "polyline",
9060
9108
  {
9061
9109
  points: linePoints,
@@ -9066,7 +9114,7 @@ function ITLineBarChart({
9066
9114
  strokeLinejoin: "round"
9067
9115
  }
9068
9116
  ),
9069
- data.map((d, i) => /* @__PURE__ */ jsx64(
9117
+ showLine && data.map((d, i) => /* @__PURE__ */ jsx64(
9070
9118
  "circle",
9071
9119
  {
9072
9120
  cx: x(i),
@@ -9093,12 +9141,12 @@ function ITLineBarChart({
9093
9141
  role: "status",
9094
9142
  children: [
9095
9143
  /* @__PURE__ */ jsx64("p", { className: "text-[10px] font-semibold", style: { color: "#e2e8f0" }, children: active.label }),
9096
- /* @__PURE__ */ jsxs45("p", { className: "text-[11px] tabular-nums", style: { color: lineColor }, children: [
9144
+ showLine && /* @__PURE__ */ jsxs45("p", { className: "text-[11px] tabular-nums", style: { color: lineColor }, children: [
9097
9145
  resolvedLineLabel,
9098
9146
  ": ",
9099
9147
  resolvedFormatValue(active.line)
9100
9148
  ] }),
9101
- /* @__PURE__ */ jsxs45("p", { className: "text-[11px] tabular-nums", style: { color: "#93c5fd" }, children: [
9149
+ showBars && /* @__PURE__ */ jsxs45("p", { className: "text-[11px] tabular-nums", style: { color: "#93c5fd" }, children: [
9102
9150
  resolvedBarLabel,
9103
9151
  ": ",
9104
9152
  resolvedFormatValue(active.bar)
@@ -9107,11 +9155,11 @@ function ITLineBarChart({
9107
9155
  }
9108
9156
  ),
9109
9157
  /* @__PURE__ */ jsxs45("ul", { className: "flex flex-wrap items-center gap-4 text-[11px]", style: { color: "#475569" }, children: [
9110
- /* @__PURE__ */ jsxs45("li", { children: [
9158
+ showLine && /* @__PURE__ */ jsxs45("li", { children: [
9111
9159
  /* @__PURE__ */ jsx64("span", { className: "h-2.5 w-2.5 rounded-sm", style: { background: lineColor }, "aria-hidden": true }),
9112
9160
  resolvedLineLabel
9113
9161
  ] }),
9114
- /* @__PURE__ */ jsxs45("li", { children: [
9162
+ showBars && /* @__PURE__ */ jsxs45("li", { children: [
9115
9163
  /* @__PURE__ */ jsx64("span", { className: "h-2.5 w-2.5 rounded-sm", style: { background: barColor }, "aria-hidden": true }),
9116
9164
  resolvedBarLabel
9117
9165
  ] })
@@ -9760,6 +9808,7 @@ function ITTable({
9760
9808
 
9761
9809
  // src/components/atoms/textarea/textarea.tsx
9762
9810
  import clsx46 from "clsx";
9811
+ import { forwardRef as forwardRef2 } from "react";
9763
9812
  import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
9764
9813
  var resizeMap = {
9765
9814
  none: "resize-none",
@@ -9767,7 +9816,7 @@ var resizeMap = {
9767
9816
  horizontal: "resize-x",
9768
9817
  both: "resize"
9769
9818
  };
9770
- function ITTextarea({
9819
+ var ITTextarea = forwardRef2(function ITTextarea2({
9771
9820
  value,
9772
9821
  onChange,
9773
9822
  label,
@@ -9778,13 +9827,16 @@ function ITTextarea({
9778
9827
  className,
9779
9828
  name,
9780
9829
  maxLength,
9781
- resize = "vertical"
9782
- }) {
9830
+ resize = "vertical",
9831
+ onKeyDown,
9832
+ autoFocus = false
9833
+ }, ref) {
9783
9834
  return /* @__PURE__ */ jsxs47("div", { className: clsx46("flex flex-col gap-1.5", className), children: [
9784
9835
  label && /* @__PURE__ */ jsx66(ITText, { as: "label", className: inputLabel(!!error), htmlFor: name, children: label }),
9785
9836
  /* @__PURE__ */ jsx66(
9786
9837
  "textarea",
9787
9838
  {
9839
+ ref,
9788
9840
  id: name,
9789
9841
  name,
9790
9842
  value,
@@ -9793,6 +9845,8 @@ function ITTextarea({
9793
9845
  rows,
9794
9846
  disabled,
9795
9847
  maxLength,
9848
+ onKeyDown,
9849
+ autoFocus,
9796
9850
  className: clsx46(
9797
9851
  "w-full border border-solid transition-all duration-200 rounded-lg px-3 py-2 text-sm outline-none",
9798
9852
  "focus:ring-2",
@@ -9804,7 +9858,9 @@ function ITTextarea({
9804
9858
  ),
9805
9859
  error && /* @__PURE__ */ jsx66(ITText, { as: "span", className: inputError, children: error })
9806
9860
  ] });
9807
- }
9861
+ });
9862
+ ITTextarea.displayName = "ITTextarea";
9863
+ var textarea_default = ITTextarea;
9808
9864
 
9809
9865
  // src/components/molecules/tabs/tabs.tsx
9810
9866
  import { useState as useState31 } from "react";
@@ -12171,7 +12227,7 @@ function EditorToggle({
12171
12227
  }
12172
12228
 
12173
12229
  // src/json-renderer/kernel/SchemaRenderer.tsx
12174
- import { useEffect as useEffect18, useMemo as useMemo16, useRef as useRef23 } from "react";
12230
+ import { useCallback as useCallback12, useEffect as useEffect18, useMemo as useMemo16, useRef as useRef23, useState as useState38 } from "react";
12175
12231
 
12176
12232
  // src/types/loader.types.ts
12177
12233
  var sizeClasses = {
@@ -12482,7 +12538,7 @@ var AXZY_CATALOG_ENTRIES = [
12482
12538
  },
12483
12539
  {
12484
12540
  type: "ITFlex",
12485
- component: ITFlex,
12541
+ component: flex_default,
12486
12542
  children: true,
12487
12543
  summary: "Contenedor flex completo.",
12488
12544
  props: {
@@ -12615,6 +12671,192 @@ var AXZY_EXCLUDED_TYPES = {
12615
12671
  var axzyCatalog = createCatalog(AXZY_CATALOG_ENTRIES, AXZY_EXCLUDED_TYPES);
12616
12672
  var axzyCatalogTypes = Object.keys(axzyCatalog.entries);
12617
12673
 
12674
+ // src/json-renderer/shared/errors.ts
12675
+ var JsonEngineError = class extends Error {
12676
+ constructor(code, message, path, hint) {
12677
+ super(`${code} ${path ? `en ${path}: ` : ""}${message}`);
12678
+ /** Código estable del catálogo de avisos. */
12679
+ __publicField(this, "code");
12680
+ /** Ruta del esquema donde se produjo. */
12681
+ __publicField(this, "path");
12682
+ /** Sugerencia accionable. */
12683
+ __publicField(this, "hint");
12684
+ this.name = "JsonEngineError";
12685
+ this.code = code;
12686
+ this.path = path;
12687
+ this.hint = hint;
12688
+ }
12689
+ /** Convierte el error en el aviso que consume la interfaz y el informe. */
12690
+ toIssue(severity = "error") {
12691
+ return {
12692
+ code: this.code,
12693
+ severity,
12694
+ message: this.message.replace(/^JR\d{3}\s?(en .*?: )?/, ""),
12695
+ path: this.path,
12696
+ hint: this.hint
12697
+ };
12698
+ }
12699
+ };
12700
+ function issue(code, message, path = "", options = {}) {
12701
+ return {
12702
+ code,
12703
+ severity: options.severity ?? "error",
12704
+ message,
12705
+ path,
12706
+ hint: options.hint
12707
+ };
12708
+ }
12709
+
12710
+ // src/json-renderer/shared/paths.ts
12711
+ function pushPath(path, segment) {
12712
+ return [...path, segment];
12713
+ }
12714
+ function formatPath(path) {
12715
+ let out = "";
12716
+ for (const segment of path) {
12717
+ if (typeof segment === "number") out += `[${segment}]`;
12718
+ else out += out ? `.${segment}` : segment;
12719
+ }
12720
+ return out;
12721
+ }
12722
+ function parsePath(rendered) {
12723
+ if (!rendered) return [];
12724
+ return rendered.split(/\.(?![^[]*])/).flatMap((part) => {
12725
+ const match = part.match(/^([^[\]]*)((?:\[\d+\])*)$/);
12726
+ if (!match) return [part];
12727
+ const [, key, indexes] = match;
12728
+ const segments = key ? [key] : [];
12729
+ for (const index of indexes.match(/\d+/g) ?? []) segments.push(Number(index));
12730
+ return segments;
12731
+ });
12732
+ }
12733
+ function readPath(source, path) {
12734
+ let cursor = source;
12735
+ for (const segment of path) {
12736
+ if (cursor === null || typeof cursor !== "object") return void 0;
12737
+ cursor = cursor[segment];
12738
+ }
12739
+ return cursor;
12740
+ }
12741
+ function hasPath(source, path) {
12742
+ if (path.length === 0) return true;
12743
+ const parent = readPath(source, path.slice(0, -1));
12744
+ if (parent === null || typeof parent !== "object") return false;
12745
+ return Object.prototype.hasOwnProperty.call(parent, path[path.length - 1]);
12746
+ }
12747
+ function propPath(nodePath, prop) {
12748
+ return pushPath(pushPath(nodePath, "props"), prop);
12749
+ }
12750
+
12751
+ // src/json-renderer/binding/resolveValue.ts
12752
+ var CLAVES_DE_RED = ["url", "endpoint", "href", "src"];
12753
+ var SUPPORTED_REFERENCES = ["$source", "$state", "$param"];
12754
+ function own(record, key) {
12755
+ return record !== void 0 && Object.prototype.hasOwnProperty.call(record, key);
12756
+ }
12757
+ function isDollarReference(value) {
12758
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
12759
+ return Object.keys(value).some((key) => key.startsWith("$"));
12760
+ }
12761
+ function referenceIssue(message, path, hint) {
12762
+ return issue("JR032", message, formatPath(path), { severity: "warning", hint });
12763
+ }
12764
+ function createBindingResolver(scope) {
12765
+ const readValue = (table, kind, key, path) => {
12766
+ if (own(table, key)) return table[key];
12767
+ scope.report(
12768
+ referenceIssue(
12769
+ `La referencia \`${kind}: "${key}"\` no tiene valor.`,
12770
+ path,
12771
+ kind === "$state" ? "Declara el valor en `state` del esquema." : "El host debe pasar el par\xE1metro en `params`."
12772
+ )
12773
+ );
12774
+ return void 0;
12775
+ };
12776
+ const resolveParams = (declared, path) => {
12777
+ const resolved = {};
12778
+ for (const [name, raw] of Object.entries(declared ?? {})) {
12779
+ if (!isDollarReference(raw)) {
12780
+ resolved[name] = raw;
12781
+ continue;
12782
+ }
12783
+ const [key] = Object.keys(raw).filter((candidate) => candidate.startsWith("$"));
12784
+ if (key === "$state" && typeof raw[key] === "string") {
12785
+ const value = readValue(scope.state, "$state", raw[key], path);
12786
+ if (value !== void 0) resolved[name] = value;
12787
+ } else if (key === "$param" && typeof raw[key] === "string") {
12788
+ const value = readValue(scope.params, "$param", raw[key], path);
12789
+ if (value !== void 0) resolved[name] = value;
12790
+ } else {
12791
+ scope.report(
12792
+ referenceIssue(
12793
+ "Un par\xE1metro de fuente solo admite valores, `$state` o `$param`.",
12794
+ path,
12795
+ "Las fuentes no se encadenan: declara la fuente sin referencias a otras fuentes."
12796
+ )
12797
+ );
12798
+ }
12799
+ }
12800
+ return resolved;
12801
+ };
12802
+ const failingLoader = (message, path, hint) => {
12803
+ scope.report(issue("JR030", message, formatPath(path), { severity: "error", hint }));
12804
+ return () => Promise.reject(new Error(message));
12805
+ };
12806
+ const sourceLoader = (name, path) => {
12807
+ if (!own(scope.data, name)) {
12808
+ return failingLoader(
12809
+ `La fuente \`${name}\` no est\xE1 declarada en \`data\`.`,
12810
+ path,
12811
+ "Decl\xE1rala en `data` del esquema con el `handler` que registra el host."
12812
+ );
12813
+ }
12814
+ const declared = scope.data[name];
12815
+ const claveDeRed = Object.keys(declared).find((clave) => CLAVES_DE_RED.includes(clave));
12816
+ if (claveDeRed) {
12817
+ scope.report(
12818
+ issue("JR031", `El esquema declara \`${claveDeRed}\` en la fuente "${name}": las fuentes no pueden pedir red.`, formatPath(path), {
12819
+ severity: "error",
12820
+ hint: "Una fuente solo nombra un `handler` que registra el host."
12821
+ })
12822
+ );
12823
+ return () => Promise.reject(new Error(`La fuente "${name}" no puede pedir red.`));
12824
+ }
12825
+ const handler = own(scope.handlers, declared.handler) ? scope.handlers[declared.handler] : void 0;
12826
+ if (typeof handler !== "function") {
12827
+ return failingLoader(
12828
+ `El handler \`${declared.handler}\` no est\xE1 registrado por el host.`,
12829
+ path,
12830
+ "El host debe registrarlo en `dataHandlers` del renderizador."
12831
+ );
12832
+ }
12833
+ const params = resolveParams(declared.params, path);
12834
+ return (query) => new Promise((resolve) => resolve(handler(query, params)));
12835
+ };
12836
+ const resolveReference = (ref, path) => {
12837
+ const keys = Object.keys(ref).filter((key2) => key2.startsWith("$"));
12838
+ const [key] = keys;
12839
+ if (keys.length !== 1 || !SUPPORTED_REFERENCES.includes(key) || typeof ref[key] !== "string") {
12840
+ scope.report(
12841
+ referenceIssue(
12842
+ `Referencia no soportada: ${keys.join(", ") || "sin operador"}.`,
12843
+ path,
12844
+ "Soportadas: `$source`, `$state` y `$param`. Los dem\xE1s operadores llegan con las acciones y las tablas."
12845
+ )
12846
+ );
12847
+ return void 0;
12848
+ }
12849
+ const name = ref[key];
12850
+ if (key === "$source") return sourceLoader(name, path);
12851
+ if (key === "$state") return readValue(scope.state, "$state", name, path);
12852
+ return readValue(scope.params, "$param", name, path);
12853
+ };
12854
+ return (value, path) => {
12855
+ if (isDollarReference(value)) return resolveReference(value, path);
12856
+ return scope.host ? scope.host(value, path) : value;
12857
+ };
12858
+ }
12859
+
12618
12860
  // src/json-renderer/shared/limits.ts
12619
12861
  var DEFAULT_LIMITS = {
12620
12862
  maxNodes: 5e3,
@@ -12658,46 +12900,25 @@ function createLimitTracker(limits = DEFAULT_LIMITS) {
12658
12900
  };
12659
12901
  }
12660
12902
 
12661
- // src/json-renderer/kernel/NodeBoundary.tsx
12662
- import React16 from "react";
12663
-
12664
- // src/json-renderer/shared/errors.ts
12665
- var JsonEngineError = class extends Error {
12666
- constructor(code, message, path, hint) {
12667
- super(`${code} ${path ? `en ${path}: ` : ""}${message}`);
12668
- /** Código estable del catálogo de avisos. */
12669
- __publicField(this, "code");
12670
- /** Ruta del esquema donde se produjo. */
12671
- __publicField(this, "path");
12672
- /** Sugerencia accionable. */
12673
- __publicField(this, "hint");
12674
- this.name = "JsonEngineError";
12675
- this.code = code;
12676
- this.path = path;
12677
- this.hint = hint;
12903
+ // src/json-renderer/kernel/capabilities.ts
12904
+ function capacidadesRequeridas(requires) {
12905
+ if (requires === void 0 || requires === null) return [];
12906
+ if (typeof requires === "string") return requires === "" ? null : [requires];
12907
+ if (Array.isArray(requires) && requires.every((item) => typeof item === "string" && item !== "")) {
12908
+ return requires;
12678
12909
  }
12679
- /** Convierte el error en el aviso que consume la interfaz y el informe. */
12680
- toIssue(severity = "error") {
12681
- return {
12682
- code: this.code,
12683
- severity,
12684
- message: this.message.replace(/^JR\d{3}\s?(en .*?: )?/, ""),
12685
- path: this.path,
12686
- hint: this.hint
12687
- };
12688
- }
12689
- };
12690
- function issue(code, message, path = "", options = {}) {
12691
- return {
12692
- code,
12693
- severity: options.severity ?? "error",
12694
- message,
12695
- path,
12696
- hint: options.hint
12697
- };
12910
+ return null;
12911
+ }
12912
+ function faltanCapacidades(requires, concedidas) {
12913
+ const requeridas = capacidadesRequeridas(requires);
12914
+ if (requeridas === null) return ["(requires no v\xE1lido)"];
12915
+ if (requeridas.length === 0) return [];
12916
+ const conjunto = new Set(concedidas ?? []);
12917
+ return requeridas.filter((capacidad) => !conjunto.has(capacidad));
12698
12918
  }
12699
12919
 
12700
12920
  // src/json-renderer/kernel/NodeBoundary.tsx
12921
+ import React16 from "react";
12701
12922
  var NodeBoundary = class extends React16.Component {
12702
12923
  constructor() {
12703
12924
  super(...arguments);
@@ -13045,48 +13266,7 @@ function isNodePending(node) {
13045
13266
  }
13046
13267
 
13047
13268
  // src/json-renderer/kernel/renderNode.tsx
13048
- import React17 from "react";
13049
-
13050
- // src/json-renderer/shared/paths.ts
13051
- function pushPath(path, segment) {
13052
- return [...path, segment];
13053
- }
13054
- function formatPath(path) {
13055
- let out = "";
13056
- for (const segment of path) {
13057
- if (typeof segment === "number") out += `[${segment}]`;
13058
- else out += out ? `.${segment}` : segment;
13059
- }
13060
- return out;
13061
- }
13062
- function parsePath(rendered) {
13063
- if (!rendered) return [];
13064
- return rendered.split(/\.(?![^[]*])/).flatMap((part) => {
13065
- const match = part.match(/^([^[\]]*)((?:\[\d+\])*)$/);
13066
- if (!match) return [part];
13067
- const [, key, indexes] = match;
13068
- const segments = key ? [key] : [];
13069
- for (const index of indexes.match(/\d+/g) ?? []) segments.push(Number(index));
13070
- return segments;
13071
- });
13072
- }
13073
- function readPath(source, path) {
13074
- let cursor = source;
13075
- for (const segment of path) {
13076
- if (cursor === null || typeof cursor !== "object") return void 0;
13077
- cursor = cursor[segment];
13078
- }
13079
- return cursor;
13080
- }
13081
- function hasPath(source, path) {
13082
- if (path.length === 0) return true;
13083
- const parent = readPath(source, path.slice(0, -1));
13084
- if (parent === null || typeof parent !== "object") return false;
13085
- return Object.prototype.hasOwnProperty.call(parent, path[path.length - 1]);
13086
- }
13087
- function propPath(nodePath, prop) {
13088
- return pushPath(pushPath(nodePath, "props"), prop);
13089
- }
13269
+ import React18 from "react";
13090
13270
 
13091
13271
  // src/json-renderer/catalog/resolve.ts
13092
13272
  function isSchemaReference(value) {
@@ -13227,11 +13407,457 @@ function resolveNode(node, catalog, path) {
13227
13407
  return { ok: true, entry, props, actions, issues };
13228
13408
  }
13229
13409
 
13410
+ // src/json-renderer/kernel/slots.ts
13411
+ var SLOT_TYPE = "slot";
13412
+ function isSlotNode(node) {
13413
+ return node.type === SLOT_TYPE;
13414
+ }
13415
+ function slotName(node) {
13416
+ const name = node.props?.name;
13417
+ return typeof name === "string" && name !== "" ? name : void 0;
13418
+ }
13419
+
13420
+ // src/json-renderer/form/FormNode.tsx
13421
+ import { useState as useState37 } from "react";
13422
+
13423
+ // src/json-renderer/form/rules.ts
13424
+ var FORM_FIELD_KINDS = ["text", "email"];
13425
+ var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
13426
+ function longitudDeclarada(value) {
13427
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
13428
+ }
13429
+ function readFormFields(declared, fieldsPath) {
13430
+ const issues = [];
13431
+ const fields = [];
13432
+ if (!Array.isArray(declared)) {
13433
+ issues.push(issue("JR021", "El formulario necesita `props.fields` como lista.", formatPath(fieldsPath), { severity: "error" }));
13434
+ return { fields, issues };
13435
+ }
13436
+ const nombres = /* @__PURE__ */ new Set();
13437
+ declared.forEach((raw, index) => {
13438
+ const fieldPath = [...fieldsPath, index];
13439
+ const campo = raw;
13440
+ if (!campo || typeof campo !== "object" || typeof campo.name !== "string" || campo.name === "") {
13441
+ issues.push(issue("JR021", "Un campo del formulario no declara `name`.", formatPath(fieldPath), { severity: "error" }));
13442
+ return;
13443
+ }
13444
+ if (nombres.has(campo.name)) {
13445
+ issues.push(issue("JR021", `El campo "${campo.name}" se repite.`, formatPath(fieldPath), { severity: "error" }));
13446
+ return;
13447
+ }
13448
+ let kind = "text";
13449
+ if (campo.kind !== void 0) {
13450
+ if (typeof campo.kind === "string" && FORM_FIELD_KINDS.includes(campo.kind)) {
13451
+ kind = campo.kind;
13452
+ } else {
13453
+ issues.push(
13454
+ issue("JR011", `Tipo de campo "${String(campo.kind)}" no admitido.`, formatPath(fieldPath), {
13455
+ severity: "warning",
13456
+ hint: `Admitidos: ${FORM_FIELD_KINDS.join(", ")}. Se usa "text".`
13457
+ })
13458
+ );
13459
+ }
13460
+ }
13461
+ const minLength = longitudDeclarada(campo.minLength);
13462
+ const maxLength = longitudDeclarada(campo.maxLength);
13463
+ for (const [clave, valor, declarada] of [["minLength", campo.minLength, minLength], ["maxLength", campo.maxLength, maxLength]]) {
13464
+ if (valor !== void 0 && declarada === void 0) {
13465
+ issues.push(issue("JR011", `\`${clave}\` debe ser un entero no negativo.`, formatPath(fieldPath), { severity: "warning", hint: "Se ignora." }));
13466
+ }
13467
+ }
13468
+ if (minLength !== void 0 && maxLength !== void 0 && minLength > maxLength) {
13469
+ issues.push(issue("JR021", `El campo "${campo.name}" tiene minLength mayor que maxLength.`, formatPath(fieldPath), { severity: "error" }));
13470
+ return;
13471
+ }
13472
+ nombres.add(campo.name);
13473
+ fields.push({ name: campo.name, kind, required: campo.required === true, minLength, maxLength, label: campo.label });
13474
+ });
13475
+ return { fields, issues };
13476
+ }
13477
+ function validateField(field, value) {
13478
+ const texto = value.trim();
13479
+ if (texto === "") return field.required ? "required" : void 0;
13480
+ if (field.minLength !== void 0 && texto.length < field.minLength) return "minLength";
13481
+ if (field.maxLength !== void 0 && texto.length > field.maxLength) return "maxLength";
13482
+ if (field.kind === "email" && !EMAIL.test(texto)) return "email";
13483
+ return void 0;
13484
+ }
13485
+ function validateForm(fields, values) {
13486
+ const errores = {};
13487
+ for (const field of fields) {
13488
+ const code = validateField(field, values[field.name] ?? "");
13489
+ if (code) errores[field.name] = code;
13490
+ }
13491
+ return errores;
13492
+ }
13493
+
13494
+ // src/json-renderer/form/FormNode.tsx
13495
+ import { jsx as jsx75, jsxs as jsxs54 } from "react/jsx-runtime";
13496
+ function valorDe(evento) {
13497
+ if (typeof evento === "string") return evento;
13498
+ return evento?.target?.value?.toString() ?? "";
13499
+ }
13500
+ function FormNode({ id, fields, submitLabel, onSubmit }) {
13501
+ const { t } = useITTranslation();
13502
+ const [values, setValues] = useState37({});
13503
+ const [errors, setErrors] = useState37({});
13504
+ const [intentado, setIntentado] = useState37(false);
13505
+ const mensaje = (code, campo) => t(`jsonRenderer.form.${code}`, { min: String(campo.minLength ?? 0), max: String(campo.maxLength ?? 0) });
13506
+ const enviar = () => {
13507
+ const encontrados = validateForm(fields, values);
13508
+ setIntentado(true);
13509
+ setErrors(encontrados);
13510
+ if (Object.keys(encontrados).length === 0) onSubmit?.(values);
13511
+ };
13512
+ return /* @__PURE__ */ jsx75("div", { id, children: /* @__PURE__ */ jsxs54(ITStack, { direction: "column", spacing: 3, alignItems: "stretch", children: [
13513
+ fields.map((field) => /* @__PURE__ */ jsx75(
13514
+ ITInput,
13515
+ {
13516
+ name: field.name,
13517
+ label: field.label,
13518
+ type: field.kind === "email" ? "email" : "text",
13519
+ value: values[field.name] ?? "",
13520
+ touched: intentado,
13521
+ error: errors[field.name] ? mensaje(errors[field.name], field) : void 0,
13522
+ onChange: (evento) => {
13523
+ const valor = valorDe(evento);
13524
+ setValues((previo) => ({ ...previo, [field.name]: valor }));
13525
+ setErrors((previo) => {
13526
+ if (!previo[field.name]) return previo;
13527
+ const resto = { ...previo };
13528
+ delete resto[field.name];
13529
+ return resto;
13530
+ });
13531
+ }
13532
+ },
13533
+ field.name
13534
+ )),
13535
+ /* @__PURE__ */ jsx75(flex_default, { children: /* @__PURE__ */ jsx75(ITButton, { label: submitLabel ?? t("jsonRenderer.form.submit"), size: "sm", onClick: enviar }) })
13536
+ ] }) });
13537
+ }
13538
+
13539
+ // src/json-renderer/actions/effects.ts
13540
+ var MAX_EFFECT_DEPTH = 5;
13541
+ var EFFECT_KEYS = ["toast", "navigate", "refresh", "openOverlay", "closeOverlay", "set"];
13542
+ var EFFECT_KEYS_DEL_HOST = ["toast", "navigate", "refresh", "openOverlay", "closeOverlay"];
13543
+ function leerResultado(ruta, resultado) {
13544
+ return ruta.split(".").reduce(
13545
+ (actual, clave) => actual && typeof actual === "object" ? actual[clave] : void 0,
13546
+ resultado
13547
+ );
13548
+ }
13549
+ function resolverResultado(valor, resultado) {
13550
+ if (!valor || typeof valor !== "object" || Array.isArray(valor)) return valor;
13551
+ const objeto = valor;
13552
+ if (typeof objeto.$result === "string") return leerResultado(objeto.$result, resultado) ?? "";
13553
+ if (objeto.params && typeof objeto.params === "object") {
13554
+ const params = Object.fromEntries(
13555
+ Object.entries(objeto.params).map(([clave, valorParam]) => [
13556
+ clave,
13557
+ resolverResultado(valorParam, resultado)
13558
+ ])
13559
+ );
13560
+ return { ...objeto, params };
13561
+ }
13562
+ return valor;
13563
+ }
13564
+ function plantilla(texto, resultado) {
13565
+ return texto.replace(/\{([\w.]+)\}/g, (_, ruta) => {
13566
+ const valor = leerResultado(ruta, resultado);
13567
+ return valor === void 0 ? "" : String(valor);
13568
+ });
13569
+ }
13570
+ function efectosSueltos(declarada) {
13571
+ const sueltos = {};
13572
+ for (const clave of EFFECT_KEYS) {
13573
+ if (declarada[clave] !== void 0) sueltos[clave] = declarada[clave];
13574
+ }
13575
+ return Object.keys(sueltos).length > 0 ? sueltos : null;
13576
+ }
13577
+ function comprobarRegistro(efecto, context) {
13578
+ for (const clave of EFFECT_KEYS_DEL_HOST) {
13579
+ if (efecto[clave] === void 0) continue;
13580
+ if (typeof context.effects?.[clave] !== "function") {
13581
+ context.report(
13582
+ issue("JR040", `El host no implementa el efecto \`${clave}\`.`, formatPath(context.path), {
13583
+ severity: "warning",
13584
+ hint: "Reg\xEDstralo en `effects` del renderizador o quita el efecto del esquema."
13585
+ })
13586
+ );
13587
+ }
13588
+ }
13589
+ }
13590
+ function cumplirEfecto(efecto, context, resultado) {
13591
+ if (efecto.set && context.setState) {
13592
+ const cambios = {};
13593
+ for (const [clave, valor] of Object.entries(efecto.set)) {
13594
+ const conResultado = resolverResultado(valor, resultado);
13595
+ cambios[clave] = context.resolveRaw ? context.resolveRaw(conResultado, context.path) : conResultado;
13596
+ }
13597
+ context.setState(cambios);
13598
+ }
13599
+ const registro = context.effects;
13600
+ if (!registro) return;
13601
+ if (efecto.toast && registro.toast) {
13602
+ registro.toast({
13603
+ variant: efecto.toast.variant ?? "info",
13604
+ message: context.resolveText(resolverResultado(efecto.toast.message, resultado), context.path)
13605
+ });
13606
+ }
13607
+ if (typeof efecto.navigate === "string" && registro.navigate) {
13608
+ registro.navigate(plantilla(efecto.navigate, resultado));
13609
+ }
13610
+ if (typeof efecto.refresh === "string" && registro.refresh) registro.refresh(efecto.refresh);
13611
+ if (typeof efecto.openOverlay === "string" && registro.openOverlay) registro.openOverlay(efecto.openOverlay);
13612
+ if (efecto.closeOverlay !== void 0 && registro.closeOverlay) {
13613
+ registro.closeOverlay(typeof efecto.closeOverlay === "string" ? efecto.closeOverlay : void 0);
13614
+ }
13615
+ }
13616
+ function pasosDe(efectos, context) {
13617
+ const profundidad = context.depth ?? 0;
13618
+ return efectos.map((efecto) => {
13619
+ if (typeof efecto.action !== "string") {
13620
+ comprobarRegistro(efecto, context);
13621
+ return (resultado) => cumplirEfecto(efecto, context, resultado);
13622
+ }
13623
+ if (profundidad + 1 > MAX_EFFECT_DEPTH) {
13624
+ context.report(
13625
+ issue("JR042", `El encadenado de acciones supera ${MAX_EFFECT_DEPTH} niveles.`, formatPath(context.path), {
13626
+ severity: "error",
13627
+ hint: "Reduce los `then` anidados."
13628
+ })
13629
+ );
13630
+ return () => void 0;
13631
+ }
13632
+ const handler = context.resolveChained?.(efecto.action);
13633
+ if (!handler) {
13634
+ context.report(
13635
+ issue("JR040", `La acci\xF3n encadenada \`${efecto.action}\` no est\xE1 registrada por el host.`, formatPath(context.path), {
13636
+ severity: "error",
13637
+ hint: "Reg\xEDstrala en las acciones del renderizador o cambia el nombre en el esquema."
13638
+ })
13639
+ );
13640
+ return () => void 0;
13641
+ }
13642
+ const encadenada = wrapAction(handler, efecto, { ...context, depth: profundidad + 1 });
13643
+ return () => encadenada(efecto.args);
13644
+ });
13645
+ }
13646
+ function wrapAction(handler, action, context) {
13647
+ if (!action || typeof action !== "object") return handler;
13648
+ const declarada = action;
13649
+ const sueltos = efectosSueltos(declarada);
13650
+ const alTerminar = [...sueltos ? [sueltos] : [], ...Array.isArray(declarada.then) ? declarada.then : []];
13651
+ const alFallar = declarada.onError;
13652
+ if (alTerminar.length === 0 && !alFallar) return handler;
13653
+ const pasosOk = pasosDe(alTerminar, context);
13654
+ const pasoError = alFallar ? pasosDe([alFallar], context)[0] : void 0;
13655
+ const aplicar = (resultado) => pasosOk.forEach((paso) => paso(resultado));
13656
+ return (...args) => {
13657
+ let resultado;
13658
+ try {
13659
+ resultado = handler(...args);
13660
+ } catch {
13661
+ pasoError?.(void 0);
13662
+ return void 0;
13663
+ }
13664
+ if (resultado && typeof resultado.then === "function") {
13665
+ let resuelta = false;
13666
+ const limite = context.timeoutMs;
13667
+ const temporizador = limite !== void 0 && Number.isFinite(limite) ? setTimeout(() => {
13668
+ if (resuelta) return;
13669
+ resuelta = true;
13670
+ context.reportRuntime?.(
13671
+ issue("JR041", `La acci\xF3n excedi\xF3 ${limite} ms y se considera fallida.`, formatPath(context.path), {
13672
+ severity: "error",
13673
+ hint: "El host debe responder o rechazar la acci\xF3n a tiempo."
13674
+ })
13675
+ );
13676
+ pasoError?.(void 0);
13677
+ }, limite) : void 0;
13678
+ resultado.then(
13679
+ (valor) => {
13680
+ if (resuelta) return;
13681
+ resuelta = true;
13682
+ clearTimeout(temporizador);
13683
+ aplicar(valor);
13684
+ },
13685
+ () => {
13686
+ if (resuelta) return;
13687
+ resuelta = true;
13688
+ clearTimeout(temporizador);
13689
+ pasoError?.(void 0);
13690
+ }
13691
+ );
13692
+ return resultado;
13693
+ }
13694
+ aplicar(resultado);
13695
+ return resultado;
13696
+ };
13697
+ }
13698
+
13230
13699
  // src/json-renderer/kernel/renderNode.tsx
13700
+ function effectContext(options, path, node) {
13701
+ return {
13702
+ effects: options.effects,
13703
+ path,
13704
+ resolveText: (value, valuePath) => textoDe(options.resolveValue ? options.resolveValue(value, valuePath) : value),
13705
+ report: (aviso) => options.issues.push(aviso),
13706
+ // Una acción encadenada desde un efecto se resuelve con el mismo `resolveAction` del host.
13707
+ resolveChained: (name) => options.resolveAction?.(node, "chain", { action: name }, path),
13708
+ timeoutMs: options.actionTimeoutMs,
13709
+ reportRuntime: options.onIssue,
13710
+ setState: options.setState,
13711
+ resolveRaw: (value, valuePath) => options.resolveValue ? options.resolveValue(value, valuePath) : value
13712
+ };
13713
+ }
13714
+ function nombreDeAccion(action) {
13715
+ const nombre = action?.action;
13716
+ return typeof nombre === "string" ? nombre : "(sin nombre)";
13717
+ }
13718
+ function isFormNode(node) {
13719
+ return node.type === "form";
13720
+ }
13721
+ function textoDe(value) {
13722
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : "";
13723
+ }
13231
13724
  function childList(node) {
13232
13725
  if (!node || node.children === void 0 || node.children === null) return [];
13233
13726
  return Array.isArray(node.children) ? node.children : [node.children];
13234
13727
  }
13728
+ function renderSlot(node, options) {
13729
+ const { path, issues, slots, resolveValue } = options;
13730
+ const name = slotName(node);
13731
+ if (!name) {
13732
+ issues.push(
13733
+ issue("JR011", "El slot no declara `props.name`.", formatPath(propPath(path, "name")), {
13734
+ severity: "error",
13735
+ hint: 'Declara el nombre que el host registr\xF3, por ejemplo { "type": "slot", "props": { "name": "resumen" } }.'
13736
+ })
13737
+ );
13738
+ return null;
13739
+ }
13740
+ const Component = slots && Object.prototype.hasOwnProperty.call(slots, name) ? slots[name] : void 0;
13741
+ if (!Component) {
13742
+ issues.push(
13743
+ issue("JR010", `El slot \`${name}\` no est\xE1 registrado por el host.`, formatPath(path), {
13744
+ severity: "error",
13745
+ hint: "El host debe registrarlo en `slots` del renderizador."
13746
+ })
13747
+ );
13748
+ return null;
13749
+ }
13750
+ const props = {};
13751
+ for (const [key, raw] of Object.entries(node.props ?? {})) {
13752
+ if (key === "name") continue;
13753
+ props[key] = resolveValue ? resolveValue(raw, path) : raw;
13754
+ }
13755
+ return React18.createElement(Component, { key: node.id ?? path.join("-"), ...props });
13756
+ }
13757
+ function renderForm(node, options) {
13758
+ const { path, issues, resolveValue, resolveAction } = options;
13759
+ const { fields: declarados, issues: avisos } = readFormFields(node.props?.fields, [...path, "props", "fields"]);
13760
+ issues.push(...avisos);
13761
+ const campos = declarados.map((campo, index) => {
13762
+ const etiqueta = resolveValue ? resolveValue(campo.label, [...path, "props", "fields", index]) : campo.label;
13763
+ return {
13764
+ name: campo.name,
13765
+ kind: campo.kind,
13766
+ required: campo.required,
13767
+ minLength: campo.minLength,
13768
+ maxLength: campo.maxLength,
13769
+ label: textoDe(etiqueta) || campo.name
13770
+ };
13771
+ });
13772
+ const textoEnvio = node.props?.submitLabel;
13773
+ const submitLabel = textoDe(resolveValue ? resolveValue(textoEnvio, path) : textoEnvio) || void 0;
13774
+ const accion = resolveAction?.(node, "onSubmit", node.props?.onSubmit, path);
13775
+ if (node.props?.onSubmit !== void 0 && typeof accion !== "function") {
13776
+ issues.push(
13777
+ issue("JR040", `La acci\xF3n "${nombreDeAccion(node.props.onSubmit)}" no est\xE1 registrada por el host.`, formatPath(propPath(path, "onSubmit")), {
13778
+ severity: "warning",
13779
+ hint: "Reg\xEDstrala en `resolveAction` del host. Sin ella, enviar el formulario no hace nada."
13780
+ })
13781
+ );
13782
+ }
13783
+ const conEfectos = accion ? wrapAction(accion, node.props?.onSubmit, effectContext(options, path, node)) : void 0;
13784
+ return React18.createElement(FormNode, {
13785
+ key: node.id ?? path.join("-"),
13786
+ id: node.id,
13787
+ fields: campos,
13788
+ submitLabel,
13789
+ onSubmit: conEfectos ? (valores) => conEfectos(valores) : void 0
13790
+ });
13791
+ }
13792
+ function prepararColumnas(columnas, node, options, path) {
13793
+ if (!Array.isArray(columnas)) return columnas;
13794
+ return columnas.map((columna, indice) => {
13795
+ if (!columna || typeof columna !== "object") return columna;
13796
+ const declarada = columna;
13797
+ if (declarada.type !== "actions" || !Array.isArray(declarada.rowActions)) return columna;
13798
+ const colPath = [...path, "props", "columns", indice];
13799
+ const botones = declarada.rowActions.flatMap((raw, indiceAccion) => {
13800
+ const accion = raw;
13801
+ const rutaAccion = [...colPath, "rowActions", indiceAccion];
13802
+ if (!accion || typeof accion.action !== "string" || accion.action === "") {
13803
+ options.issues.push(issue("JR021", "Un bot\xF3n de fila no declara `action`.", formatPath(rutaAccion), { severity: "error" }));
13804
+ return [];
13805
+ }
13806
+ const faltan = faltanCapacidades(accion.requires, options.capabilities);
13807
+ if (faltan.length > 0) {
13808
+ options.issues.push(
13809
+ issue("JR061", `El bot\xF3n de fila "${accion.action}" exige ${faltan.join(", ")}, que no est\xE1 concedido.`, formatPath(rutaAccion), {
13810
+ severity: "warning",
13811
+ hint: "Concede la capacidad con la prop `capabilities` del renderizador."
13812
+ })
13813
+ );
13814
+ return [];
13815
+ }
13816
+ const handler = options.resolveAction?.(node, `fila:${accion.action}`, accion, rutaAccion);
13817
+ if (typeof handler !== "function") {
13818
+ options.issues.push(
13819
+ issue("JR040", `La acci\xF3n de fila "${accion.action}" no est\xE1 registrada por el host.`, formatPath(rutaAccion), {
13820
+ severity: "warning",
13821
+ hint: "Reg\xEDstrala en `resolveAction` del host, o quita el bot\xF3n del esquema."
13822
+ })
13823
+ );
13824
+ return [];
13825
+ }
13826
+ const etiqueta = textoDe(options.resolveValue ? options.resolveValue(accion.label, rutaAccion) : accion.label);
13827
+ return [
13828
+ {
13829
+ clave: String(indiceAccion),
13830
+ etiqueta: etiqueta || accion.action,
13831
+ color: typeof accion.color === "string" ? accion.color : "secondary",
13832
+ variante: typeof accion.variant === "string" ? accion.variant : "outlined",
13833
+ ejecutar: wrapAction(handler, accion, effectContext(options, rutaAccion, node))
13834
+ }
13835
+ ];
13836
+ });
13837
+ const copia = { ...declarada };
13838
+ delete copia.rowActions;
13839
+ const etiquetaColumna = textoDe(options.resolveValue ? options.resolveValue(copia.label, colPath) : copia.label);
13840
+ const Boton = ITButton;
13841
+ return {
13842
+ ...copia,
13843
+ label: etiquetaColumna || String(copia.key ?? ""),
13844
+ actions: (fila) => React18.createElement(
13845
+ React18.Fragment,
13846
+ null,
13847
+ botones.map(
13848
+ (boton) => React18.createElement(Boton, {
13849
+ key: boton.clave,
13850
+ label: boton.etiqueta,
13851
+ size: "sm",
13852
+ variant: boton.variante,
13853
+ color: boton.color,
13854
+ onClick: () => boton.ejecutar(fila)
13855
+ })
13856
+ )
13857
+ )
13858
+ };
13859
+ });
13860
+ }
13235
13861
  function renderNode(node, options) {
13236
13862
  const { catalog, path, issues, renderChildren } = options;
13237
13863
  if (!node || typeof node !== "object") {
@@ -13240,6 +13866,12 @@ function renderNode(node, options) {
13240
13866
  if (isNodePending(node)) {
13241
13867
  return options.pendingFallback ?? null;
13242
13868
  }
13869
+ if (isSlotNode(node)) {
13870
+ return renderSlot(node, options);
13871
+ }
13872
+ if (isFormNode(node)) {
13873
+ return renderForm(node, options);
13874
+ }
13243
13875
  const resolved = resolveNode(node, catalog, path);
13244
13876
  issues.push(...resolved.issues);
13245
13877
  if (!resolved.ok) {
@@ -13250,15 +13882,37 @@ function renderNode(node, options) {
13250
13882
  for (const [name, value] of Object.entries(props)) {
13251
13883
  finalProps[name] = options.resolveValue ? options.resolveValue(value, path) : value;
13252
13884
  }
13885
+ if (node.type === "ITDataTable" && finalProps.columns !== void 0) {
13886
+ finalProps.columns = prepararColumnas(finalProps.columns, node, options, path);
13887
+ }
13253
13888
  for (const [name, action] of Object.entries(actions)) {
13889
+ const faltan = faltanCapacidades(action?.requires, options.capabilities);
13890
+ if (faltan.length > 0) {
13891
+ issues.push(
13892
+ issue("JR061", `La acci\xF3n "${nombreDeAccion(action)}" exige ${faltan.join(", ")}, que no est\xE1 concedido.`, formatPath(propPath(path, name)), {
13893
+ severity: "warning",
13894
+ hint: "Concede la capacidad con la prop `capabilities` del renderizador. Sin ella, la acci\xF3n no se ejecuta."
13895
+ })
13896
+ );
13897
+ continue;
13898
+ }
13254
13899
  const handler = options.resolveAction?.(node, name, action, path);
13255
- if (typeof handler === "function") finalProps[name] = handler;
13900
+ if (typeof handler === "function") {
13901
+ finalProps[name] = wrapAction(handler, action, effectContext(options, path, node));
13902
+ } else {
13903
+ issues.push(
13904
+ issue("JR040", `La acci\xF3n "${nombreDeAccion(action)}" no est\xE1 registrada por el host.`, formatPath(propPath(path, name)), {
13905
+ severity: "warning",
13906
+ hint: "Reg\xEDstrala en `resolveAction` del host, o quita la prop del esquema."
13907
+ })
13908
+ );
13909
+ }
13256
13910
  }
13257
13911
  const content = renderChildren ? renderChildren(node, path) : null;
13258
13912
  const rawText = entry.text && node.text !== void 0 ? node.text : void 0;
13259
13913
  const text = rawText === void 0 ? void 0 : options.resolveValue ? options.resolveValue(rawText, path) : rawText;
13260
13914
  const children = content ?? text;
13261
- const element = React17.createElement(
13915
+ const element = React18.createElement(
13262
13916
  entry.component,
13263
13917
  { ...finalProps, key: node.id ?? path.join("-"), id: node.id },
13264
13918
  children
@@ -13314,7 +13968,7 @@ function countPendingNodes(schema) {
13314
13968
  }
13315
13969
 
13316
13970
  // src/json-renderer/kernel/SchemaRenderer.tsx
13317
- import { Fragment as Fragment13, jsx as jsx75 } from "react/jsx-runtime";
13971
+ import { Fragment as Fragment13, jsx as jsx76 } from "react/jsx-runtime";
13318
13972
  function renderTree(node, path, context, level) {
13319
13973
  if (!node || typeof node !== "object") return null;
13320
13974
  if (level > context.limits.maxDepth) return null;
@@ -13324,6 +13978,16 @@ function renderTree(node, path, context, level) {
13324
13978
  issues.push(issue2);
13325
13979
  context.onIssue?.(issue2);
13326
13980
  };
13981
+ const faltan = faltanCapacidades(node.requires, context.capabilities);
13982
+ if (faltan.length > 0) {
13983
+ reportIssue(
13984
+ issue("JR060", `Falta la capacidad ${faltan.join(", ")} para pintar \`${node.type}\`.`, formatPath(path), {
13985
+ severity: "warning",
13986
+ hint: "El host debe conceder la capacidad con la prop `capabilities`, o el nodo debe declarar un `fallback`."
13987
+ })
13988
+ );
13989
+ return node.fallback ? renderTree(node.fallback, [...path, "fallback"], context, level + 1) : null;
13990
+ }
13327
13991
  const issuesBefore = issues.length;
13328
13992
  const element = renderNode(node, {
13329
13993
  catalog: context.catalog,
@@ -13332,6 +13996,12 @@ function renderTree(node, path, context, level) {
13332
13996
  resolveValue: context.resolveValue,
13333
13997
  resolveAction: context.resolveAction,
13334
13998
  pendingFallback: context.pendingFallback,
13999
+ slots: context.slots,
14000
+ effects: context.effects,
14001
+ actionTimeoutMs: context.limits.actionTimeoutMs,
14002
+ onIssue: context.onIssue,
14003
+ setState: context.setState,
14004
+ capabilities: context.capabilities,
13335
14005
  renderChildren: (current, currentPath) => {
13336
14006
  const children = childList(current);
13337
14007
  if (children.length === 0) return void 0;
@@ -13344,7 +14014,7 @@ function renderTree(node, path, context, level) {
13344
14014
  context.onIssue?.(issues[index]);
13345
14015
  }
13346
14016
  const fallback = node.fallback ? renderTree(node.fallback, [...path, "fallback"], context, level + 1) : context.pendingFallback ?? null;
13347
- const wrapped = /* @__PURE__ */ jsx75(
14017
+ const wrapped = /* @__PURE__ */ jsx76(
13348
14018
  NodeBoundary,
13349
14019
  {
13350
14020
  path: path.join("."),
@@ -13366,6 +14036,11 @@ function ITSchemaRenderer({
13366
14036
  schema,
13367
14037
  catalog = axzyCatalog,
13368
14038
  limits,
14039
+ params,
14040
+ dataHandlers,
14041
+ slots,
14042
+ effects,
14043
+ capabilities,
13369
14044
  resolveValue,
13370
14045
  resolveAction,
13371
14046
  pendingFallback,
@@ -13373,6 +14048,21 @@ function ITSchemaRenderer({
13373
14048
  className
13374
14049
  }) {
13375
14050
  const resolvedLimits = useMemo16(() => resolveLimits(limits), [limits]);
14051
+ const [escrito, setEscrito] = useState38({
14052
+ origen: schema,
14053
+ valores: {}
14054
+ });
14055
+ const valoresPantalla = useMemo16(
14056
+ () => ({ ...schema?.state ?? {}, ...escrito.origen === schema ? escrito.valores : {} }),
14057
+ [schema, escrito]
14058
+ );
14059
+ const escribirEstado = useCallback12(
14060
+ (cambios) => setEscrito((previo) => ({
14061
+ origen: schema,
14062
+ valores: { ...previo.origen === schema ? previo.valores : {}, ...cambios }
14063
+ })),
14064
+ [schema]
14065
+ );
13376
14066
  const issues = [];
13377
14067
  const nodeIds = /* @__PURE__ */ new Set();
13378
14068
  const audit = useMemo16(
@@ -13386,16 +14076,37 @@ function ITSchemaRenderer({
13386
14076
  limits: resolvedLimits,
13387
14077
  issues,
13388
14078
  onIssue,
13389
- resolveValue,
14079
+ // El binding escribe sus avisos (JR030, JR032) en el mismo array que el resto del render.
14080
+ resolveValue: createBindingResolver({
14081
+ data: schema?.data,
14082
+ state: valoresPantalla,
14083
+ params,
14084
+ handlers: dataHandlers,
14085
+ report: (aviso) => issues.push(aviso),
14086
+ host: resolveValue
14087
+ }),
13390
14088
  resolveAction,
13391
- pendingFallback
14089
+ pendingFallback,
14090
+ slots,
14091
+ effects,
14092
+ capabilities,
14093
+ setState: escribirEstado
13392
14094
  }),
13393
14095
  // `issues` es un array nuevo en cada render a propósito: acumular avisos
13394
14096
  // entre renders duplicaría los avisos de esquemas que no han cambiado.
13395
14097
  // eslint-disable-next-line react-hooks/exhaustive-deps
13396
- [catalog, resolvedLimits, onIssue, resolveValue, resolveAction, pendingFallback]
14098
+ [schema, params, valoresPantalla, escribirEstado, dataHandlers, slots, effects, capabilities, catalog, resolvedLimits, onIssue, resolveValue, resolveAction, pendingFallback]
13397
14099
  );
13398
- const content = schema ? (Array.isArray(schema.content) ? schema.content : [schema.content]).filter(
14100
+ const faltanRaiz = schema ? faltanCapacidades(schema.requires, capabilities) : [];
14101
+ if (faltanRaiz.length > 0) {
14102
+ issues.push(
14103
+ issue("JR060", `Falta la capacidad ${faltanRaiz.join(", ")} para esta pantalla.`, "requires", {
14104
+ severity: "error",
14105
+ hint: "Concede la capacidad con la prop `capabilities` del renderizador."
14106
+ })
14107
+ );
14108
+ }
14109
+ const content = schema && faltanRaiz.length === 0 ? (Array.isArray(schema.content) ? schema.content : [schema.content]).filter(
13399
14110
  (node) => Boolean(node) && typeof node === "object"
13400
14111
  ) : [];
13401
14112
  const children = content.slice(0, resolvedLimits.maxNodes).map((node, index) => renderTree(node, ["content", index], context, 0)).filter(Boolean);
@@ -13421,7 +14132,159 @@ function ITSchemaRenderer({
13421
14132
  for (const issue2 of all) onIssue(issue2);
13422
14133
  }, [signature, onIssue]);
13423
14134
  if (!schema || children.length === 0) return null;
13424
- return className ? /* @__PURE__ */ jsx75("div", { className, children }) : /* @__PURE__ */ jsx75(Fragment13, { children });
14135
+ return className ? /* @__PURE__ */ jsx76("div", { className, children }) : /* @__PURE__ */ jsx76(Fragment13, { children });
14136
+ }
14137
+
14138
+ // src/json-renderer/routing/routes.ts
14139
+ function joinRoutePath(parent, own2) {
14140
+ return [parent, typeof own2 === "string" ? own2 : ""].flatMap((part) => part.split("/")).filter((segment) => segment !== "").join("/");
14141
+ }
14142
+ var SEGMENT = /^(:[A-Za-z][A-Za-z0-9_]*|[A-Za-z0-9_.-]+)$/;
14143
+ function validateRoutes(input) {
14144
+ const errors = [];
14145
+ const document2 = input;
14146
+ if (!document2 || typeof document2 !== "object" || Array.isArray(document2)) {
14147
+ return [issue("JR020", "El documento de rutas debe ser un objeto.", "", { severity: "error" })];
14148
+ }
14149
+ if (typeof document2.version !== "number") {
14150
+ errors.push(issue("JR020", "El documento de rutas no declara `version`.", "version", { severity: "error" }));
14151
+ }
14152
+ if (!Array.isArray(document2.routes)) {
14153
+ errors.push(issue("JR020", "`routes` debe ser una lista.", "routes", { severity: "error" }));
14154
+ return errors;
14155
+ }
14156
+ const seen = /* @__PURE__ */ new Map();
14157
+ const visit = (route, path, parentPath, isRoot) => {
14158
+ if (!route || typeof route !== "object") {
14159
+ errors.push(issue("JR021", "La ruta no es un objeto.", path, { severity: "error" }));
14160
+ return;
14161
+ }
14162
+ if (typeof route.id !== "string" || route.id === "") {
14163
+ errors.push(issue("JR021", "La ruta no declara `id`.", path, { severity: "error" }));
14164
+ }
14165
+ if (route.path !== void 0 && route.path !== "") {
14166
+ const parts = typeof route.path === "string" ? route.path.split("/").filter(Boolean) : [];
14167
+ if (typeof route.path !== "string" || parts.some((segment) => !SEGMENT.test(segment))) {
14168
+ errors.push(issue("JR021", `El path "${String(route.path)}" no es v\xE1lido.`, `${path}.path`, { severity: "error", hint: "Usa segmentos con letras, d\xEDgitos, guiones o `:param`." }));
14169
+ }
14170
+ }
14171
+ const full = joinRoutePath(parentPath, route.path);
14172
+ if (isRoot && full === "") {
14173
+ errors.push(issue("JR021", "Una ruta ra\xEDz necesita `path`.", `${path}.path`, { severity: "error" }));
14174
+ }
14175
+ if (route.children !== void 0) {
14176
+ if (route.page !== void 0) {
14177
+ errors.push(issue("JR020", "Un grupo no lleva `page`: la pantalla va en sus hijos.", path, { severity: "error" }));
14178
+ }
14179
+ if (!Array.isArray(route.children)) {
14180
+ errors.push(issue("JR020", "`children` debe ser una lista.", `${path}.children`, { severity: "error" }));
14181
+ } else {
14182
+ route.children.forEach((child, index) => visit(child, `${path}.children[${index}]`, full, false));
14183
+ }
14184
+ } else {
14185
+ if (typeof route.page !== "string" || route.page === "") {
14186
+ errors.push(issue("JR020", "La ruta no declara `page`.", path, { severity: "error" }));
14187
+ }
14188
+ const key = `${full}?${JSON.stringify(Object.entries(route.query ?? {}).sort())}`;
14189
+ if (seen.has(key)) {
14190
+ errors.push(issue("JR020", `La ruta "${full || "/"}" se repite con la misma query (ya est\xE1 en ${seen.get(key)}).`, path, { severity: "error" }));
14191
+ } else {
14192
+ seen.set(key, path);
14193
+ }
14194
+ }
14195
+ const nav = route.nav;
14196
+ if (nav !== void 0 && (typeof nav !== "object" || nav === null || nav.label === void 0 || nav.label === null)) {
14197
+ errors.push(issue("JR021", "La entrada de men\xFA no declara `label`.", `${path}.nav`, { severity: "error" }));
14198
+ }
14199
+ };
14200
+ document2.routes.forEach((route, index) => visit(route, `routes[${index}]`, "", true));
14201
+ return errors;
14202
+ }
14203
+ function flattenRoutes(routes) {
14204
+ const flat = [];
14205
+ const visit = (route, parentPath, groups) => {
14206
+ const full = joinRoutePath(parentPath, route.path);
14207
+ if (route.children) {
14208
+ route.children.forEach((child) => visit(child, full, [...groups, route.id]));
14209
+ return;
14210
+ }
14211
+ if (typeof route.page !== "string") return;
14212
+ flat.push({
14213
+ id: route.id,
14214
+ segments: full === "" ? [] : full.split("/"),
14215
+ page: route.page,
14216
+ query: route.query ?? {},
14217
+ nav: route.nav,
14218
+ groups
14219
+ });
14220
+ };
14221
+ routes.forEach((route) => visit(route, "", []));
14222
+ return flat;
14223
+ }
14224
+
14225
+ // src/json-renderer/routing/match.ts
14226
+ function matchRoute(routes, segments, query = {}) {
14227
+ let best = null;
14228
+ let bestStatics = -1;
14229
+ let bestConstraints = -1;
14230
+ for (const route of routes) {
14231
+ if (route.segments.length !== segments.length) continue;
14232
+ const params = {};
14233
+ let statics = 0;
14234
+ let samePath = true;
14235
+ route.segments.forEach((expected, index) => {
14236
+ if (!samePath) return;
14237
+ if (expected.startsWith(":")) {
14238
+ params[expected.slice(1)] = segments[index];
14239
+ return;
14240
+ }
14241
+ statics += 1;
14242
+ samePath = expected === segments[index];
14243
+ });
14244
+ if (!samePath) continue;
14245
+ const constraints = Object.entries(route.query);
14246
+ if (!constraints.every(([key, value]) => query[key] === value)) continue;
14247
+ if (statics > bestStatics || statics === bestStatics && constraints.length > bestConstraints) {
14248
+ best = { route, params };
14249
+ bestStatics = statics;
14250
+ bestConstraints = constraints.length;
14251
+ }
14252
+ }
14253
+ return best;
14254
+ }
14255
+ function routeHref(route, params = {}) {
14256
+ const path = route.segments.map((segment) => segment.startsWith(":") ? params[segment.slice(1)] ?? segment : segment).join("/");
14257
+ const queryString = Object.entries(route.query).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
14258
+ return `/${path}${queryString ? `?${queryString}` : ""}`;
14259
+ }
14260
+
14261
+ // src/json-renderer/routing/navigation.ts
14262
+ function buildNavigationTree(routes) {
14263
+ const hrefs = new Map(flattenRoutes(routes).map((route) => [route.id, routeHref(route)]));
14264
+ const visit = (route, parentPath) => {
14265
+ const full = joinRoutePath(parentPath, route.path);
14266
+ if (route.children) {
14267
+ const children = route.children.flatMap((child) => visit(child, full));
14268
+ if (!route.nav) return children;
14269
+ return [toNode(route.id, route.nav, children, children.find((child) => child.href)?.href)];
14270
+ }
14271
+ if (!route.nav) return [];
14272
+ return [toNode(route.id, route.nav, void 0, hrefs.get(route.id))];
14273
+ };
14274
+ return routes.flatMap((route) => visit(route, ""));
14275
+ }
14276
+ function toNode(id, nav, children, href) {
14277
+ return {
14278
+ id,
14279
+ label: nav.label,
14280
+ icon: nav.icon,
14281
+ badge: nav.badge,
14282
+ href,
14283
+ ...children ? { children } : {}
14284
+ };
14285
+ }
14286
+ function navContainsRoute(entry, routeId) {
14287
+ return entry.id === routeId || (entry.children?.some((child) => navContainsRoute(child, routeId)) ?? false);
13425
14288
  }
13426
14289
 
13427
14290
  // src/json-renderer/validation/validate.ts
@@ -13432,6 +14295,17 @@ function validateNodes(node, path, catalog, errors, warnings) {
13432
14295
  return 0;
13433
14296
  }
13434
14297
  if (isNodePending(node)) return 1;
14298
+ if (node.type === "form") {
14299
+ const { issues: avisos } = readFormFields(node.props?.fields, [...path, "props", "fields"]);
14300
+ for (const item of avisos) (item.severity === "error" ? errors : warnings).push(item);
14301
+ return 0;
14302
+ }
14303
+ if (isSlotNode(node)) {
14304
+ if (!slotName(node)) {
14305
+ errors.push(issue("JR011", "El slot no declara `props.name`.", formatPath([...path, "props", "name"]), { severity: "error" }));
14306
+ }
14307
+ return 0;
14308
+ }
13435
14309
  const resolved = resolveNode(node, catalog, path);
13436
14310
  for (const item of resolved.issues) {
13437
14311
  (item.severity === "error" ? errors : warnings).push(item);
@@ -13614,8 +14488,143 @@ function formatVocabularyForPrompt(contract) {
13614
14488
  return lines.join("\n");
13615
14489
  }
13616
14490
 
14491
+ // src/json-renderer/stream/useSchemaStream.ts
14492
+ import { useEffect as useEffect19, useState as useState39 } from "react";
14493
+ var VACIO = {
14494
+ tree: null,
14495
+ status: "complete",
14496
+ broken: false,
14497
+ pendingNodes: 0,
14498
+ streaming: false,
14499
+ text: "",
14500
+ issues: []
14501
+ };
14502
+ var grabaciones = /* @__PURE__ */ new WeakMap();
14503
+ function esAsyncIterable(value) {
14504
+ return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
14505
+ }
14506
+ async function* desdeReadable(readable) {
14507
+ const reader = readable.getReader();
14508
+ try {
14509
+ for (; ; ) {
14510
+ const { done, value } = await reader.read();
14511
+ if (done) return;
14512
+ yield value;
14513
+ }
14514
+ } finally {
14515
+ await reader.cancel().catch(() => void 0);
14516
+ }
14517
+ }
14518
+ function mensajeDe(error) {
14519
+ return error instanceof Error ? error.message : String(error);
14520
+ }
14521
+ function crearGrabacion(source) {
14522
+ const iterador = typeof source === "string" ? null : esAsyncIterable(source) ? source[Symbol.asyncIterator]() : desdeReadable(source)[Symbol.asyncIterator]();
14523
+ return {
14524
+ texto: typeof source === "string" ? source : "",
14525
+ iterador,
14526
+ terminado: typeof source === "string",
14527
+ error: null,
14528
+ avisos: [],
14529
+ activos: 0,
14530
+ ultimoValido: null,
14531
+ cerrada: false,
14532
+ cancelada: false
14533
+ };
14534
+ }
14535
+ function estadoDe(grab, streaming) {
14536
+ const parcial = parsePartialSchema(grab.texto);
14537
+ if (!parcial.broken && parcial.tree) grab.ultimoValido = parcial.tree;
14538
+ return {
14539
+ tree: parcial.broken ? grab.ultimoValido : parcial.tree,
14540
+ status: parcial.status,
14541
+ broken: parcial.broken,
14542
+ pendingNodes: parcial.pendingNodes,
14543
+ streaming,
14544
+ text: grab.texto,
14545
+ issues: [...grab.avisos]
14546
+ };
14547
+ }
14548
+ function cerrarGrabacion(grab) {
14549
+ if (grab.cerrada || grab.cancelada) return;
14550
+ grab.cerrada = true;
14551
+ if (grab.error !== null) {
14552
+ grab.avisos.push(issue("JR080", `El stream fall\xF3: ${grab.error}. Se conserva el \xFAltimo \xE1rbol v\xE1lido.`, "", { severity: "error" }));
14553
+ return;
14554
+ }
14555
+ const parcial = parsePartialSchema(grab.texto);
14556
+ if (parcial.broken || parcial.status !== "complete") {
14557
+ grab.avisos.push(
14558
+ issue("JR080", "El stream termin\xF3 con el JSON sin cerrar. Se conserva el \xFAltimo \xE1rbol v\xE1lido.", "", {
14559
+ severity: "warning",
14560
+ hint: "Revisa que el emisor cierre todas las llaves y corchetes."
14561
+ })
14562
+ );
14563
+ }
14564
+ }
14565
+ async function consumir(grab, cancelado, onTrozo) {
14566
+ while (!grab.terminado && grab.iterador) {
14567
+ let paso;
14568
+ try {
14569
+ paso = await grab.iterador.next();
14570
+ } catch (error) {
14571
+ grab.error = mensajeDe(error);
14572
+ grab.terminado = true;
14573
+ break;
14574
+ }
14575
+ if (paso.done) {
14576
+ grab.terminado = true;
14577
+ break;
14578
+ }
14579
+ grab.texto += String(paso.value);
14580
+ if (!cancelado()) onTrozo();
14581
+ if (cancelado()) return;
14582
+ }
14583
+ if (grab.terminado) cerrarGrabacion(grab);
14584
+ }
14585
+ function useSchemaStream(source) {
14586
+ const [estado, setEstado] = useState39(VACIO);
14587
+ useEffect19(() => {
14588
+ if (source === null || source === void 0) {
14589
+ setEstado(VACIO);
14590
+ return;
14591
+ }
14592
+ let registro;
14593
+ if (typeof source === "string") {
14594
+ registro = crearGrabacion(source);
14595
+ } else {
14596
+ const existente = grabaciones.get(source);
14597
+ registro = existente ?? crearGrabacion(source);
14598
+ if (!existente) grabaciones.set(source, registro);
14599
+ }
14600
+ registro.activos += 1;
14601
+ let cancelado = false;
14602
+ const proceso = consumir(
14603
+ registro,
14604
+ () => cancelado,
14605
+ () => setEstado(estadoDe(registro, true))
14606
+ );
14607
+ setEstado(estadoDe(registro, !registro.terminado));
14608
+ void proceso.then(() => {
14609
+ if (!cancelado) setEstado(estadoDe(registro, false));
14610
+ });
14611
+ return () => {
14612
+ cancelado = true;
14613
+ registro.activos -= 1;
14614
+ setTimeout(() => {
14615
+ if (registro.activos === 0 && !registro.terminado && registro.iterador) {
14616
+ registro.terminado = true;
14617
+ registro.cancelada = true;
14618
+ void registro.iterador.return?.(void 0);
14619
+ }
14620
+ }, 0);
14621
+ };
14622
+ }, [source]);
14623
+ return estado;
14624
+ }
14625
+
13617
14626
  // src/components/organisms/dropfile/dropfile.tsx
13618
- import { useState as useState37, useEffect as useEffect19 } from "react";
14627
+ import { useState as useState40, useEffect as useEffect20 } from "react";
13619
14628
  import { useDropzone } from "react-dropzone";
13620
14629
  import clsx54 from "clsx";
13621
14630
 
@@ -13645,11 +14654,12 @@ var UploadStatus = /* @__PURE__ */ ((UploadStatus2) => {
13645
14654
  })(UploadStatus || {});
13646
14655
 
13647
14656
  // src/components/organisms/dropfile/dropfile.tsx
13648
- import { Fragment as Fragment14, jsx as jsx76, jsxs as jsxs54 } from "react/jsx-runtime";
14657
+ import { Fragment as Fragment14, jsx as jsx77, jsxs as jsxs55 } from "react/jsx-runtime";
13649
14658
  var ITDropfile = ({
13650
14659
  onFileSelect,
13651
14660
  onCancel,
13652
14661
  onSubmit,
14662
+ autoUpload = false,
13653
14663
  contentClassName,
13654
14664
  containerClassName,
13655
14665
  acceptedFileTypes = ["application/pdf" /* PDF */, "application/vnd.ms-excel" /* XLS */, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" /* XLSX */, "image/jpg" /* JPG */, "image/png" /* PNG */, "image/jpeg" /* JPEG */],
@@ -13662,15 +14672,15 @@ var ITDropfile = ({
13662
14672
  modalTitle
13663
14673
  }) => {
13664
14674
  const { t } = useITTranslation();
13665
- const [isModalOpen, setIsModalOpen] = useState37(false);
13666
- const [selectedFile, setSelectedFile] = useState37(null);
13667
- const [fileType, setFileType] = useState37(null);
13668
- const [imagePreview, setImagePreview] = useState37(initialPreviewUrl || null);
13669
- const [isConfirmed, setIsConfirmed] = useState37(false);
13670
- const [internalUploadStatus, setInternalUploadStatus] = useState37(
14675
+ const [isModalOpen, setIsModalOpen] = useState40(false);
14676
+ const [selectedFile, setSelectedFile] = useState40(null);
14677
+ const [fileType, setFileType] = useState40(null);
14678
+ const [imagePreview, setImagePreview] = useState40(initialPreviewUrl || null);
14679
+ const [isConfirmed, setIsConfirmed] = useState40(false);
14680
+ const [internalUploadStatus, setInternalUploadStatus] = useState40(
13671
14681
  initialPreviewUrl ? "subido" /* UPLOADED */ : "pendiente" /* PENDING */
13672
14682
  );
13673
- useEffect19(() => {
14683
+ useEffect20(() => {
13674
14684
  if (initialPreviewUrl && !selectedFile) {
13675
14685
  setImagePreview(initialPreviewUrl);
13676
14686
  if (externalStatus === void 0) setInternalUploadStatus("subido" /* UPLOADED */);
@@ -13785,11 +14795,23 @@ var ITDropfile = ({
13785
14795
  }
13786
14796
  };
13787
14797
  const { label, color, dotColor } = config2[status];
13788
- return /* @__PURE__ */ jsxs54("div", { className: `inline-flex items-center gap-2 px-2.5 py-1 rounded-full border ${color}`, children: [
13789
- /* @__PURE__ */ jsx76("div", { className: `w-2 h-2 rounded-full ${dotColor}` }),
13790
- /* @__PURE__ */ jsx76(ITText, { as: "span", className: "text-xs font-medium flex items-center gap-1.5", children: label })
14798
+ return /* @__PURE__ */ jsxs55("div", { className: `inline-flex items-center gap-2 px-2.5 py-1 rounded-full border ${color}`, children: [
14799
+ /* @__PURE__ */ jsx77("div", { className: `w-2 h-2 rounded-full ${dotColor}` }),
14800
+ /* @__PURE__ */ jsx77(ITText, { as: "span", className: "text-xs font-medium flex items-center gap-1.5", children: label })
13791
14801
  ] });
13792
14802
  };
14803
+ const runAutoUpload = async (file) => {
14804
+ setIsConfirmed(true);
14805
+ setUploadStatus("subiendo" /* UPLOADING */);
14806
+ try {
14807
+ onFileSelect(file);
14808
+ await onSubmit?.(file);
14809
+ setUploadStatus("subido" /* UPLOADED */);
14810
+ } catch (error) {
14811
+ setUploadStatus("error" /* ERROR */);
14812
+ console.error("Error al subir archivo:", error);
14813
+ }
14814
+ };
13793
14815
  const onDrop = (acceptedFiles) => {
13794
14816
  const file = acceptedFiles[0];
13795
14817
  if (file) {
@@ -13805,6 +14827,7 @@ var ITDropfile = ({
13805
14827
  const previewUrl = URL.createObjectURL(file);
13806
14828
  setImagePreview(previewUrl);
13807
14829
  }
14830
+ if (autoUpload) void runAutoUpload(file);
13808
14831
  } else {
13809
14832
  alert(t("dropfile.fileTypeNotAllowed"));
13810
14833
  setSelectedFile(null);
@@ -13819,12 +14842,12 @@ var ITDropfile = ({
13819
14842
  accept: getAcceptedFileTypes(),
13820
14843
  maxFiles: 1
13821
14844
  });
13822
- useEffect19(() => {
14845
+ useEffect20(() => {
13823
14846
  const renderPDF = async () => {
13824
14847
  };
13825
14848
  renderPDF();
13826
14849
  }, [selectedFile, fileType]);
13827
- useEffect19(() => {
14850
+ useEffect20(() => {
13828
14851
  return () => {
13829
14852
  if (imagePreview) {
13830
14853
  URL.revokeObjectURL(imagePreview);
@@ -13861,7 +14884,7 @@ var ITDropfile = ({
13861
14884
  const handleDelete = () => {
13862
14885
  handleCancel();
13863
14886
  };
13864
- useEffect19(() => {
14887
+ useEffect20(() => {
13865
14888
  if (view === "button" && isConfirmed && uploadStatus === "subido" /* UPLOADED */) {
13866
14889
  const timeout = setTimeout(() => {
13867
14890
  setIsModalOpen(false);
@@ -13878,21 +14901,21 @@ var ITDropfile = ({
13878
14901
  return () => clearTimeout(timeout);
13879
14902
  }
13880
14903
  }, [view, isConfirmed, uploadStatus, externalStatus, onStatusChange]);
13881
- const headerRow = /* @__PURE__ */ jsxs54("div", { className: "flex items-center justify-between mb-2", children: [
13882
- /* @__PURE__ */ jsxs54("label", { className: "block text-sm font-semibold text-secondary-700", children: [
13883
- /* @__PURE__ */ jsxs54(ITText, { as: "span", children: [
14904
+ const headerRow = /* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between mb-2", children: [
14905
+ /* @__PURE__ */ jsxs55("label", { className: "block text-sm font-semibold text-secondary-700", children: [
14906
+ /* @__PURE__ */ jsxs55(ITText, { as: "span", children: [
13884
14907
  t("dropfile.upload"),
13885
14908
  " "
13886
14909
  ] }),
13887
- /* @__PURE__ */ jsxs54(ITText, { as: "span", className: "text-secondary-400 font-normal text-xs", children: [
14910
+ /* @__PURE__ */ jsxs55(ITText, { as: "span", className: "text-secondary-400 font-normal text-xs", children: [
13888
14911
  "(",
13889
14912
  getFileExtensions(),
13890
14913
  ")"
13891
14914
  ] })
13892
14915
  ] }),
13893
- showStatusBadge && selectedFile && /* @__PURE__ */ jsx76(StatusBadge, { status: uploadStatus })
14916
+ showStatusBadge && selectedFile && /* @__PURE__ */ jsx77(StatusBadge, { status: uploadStatus })
13894
14917
  ] });
13895
- const dropZoneOrPreview = /* @__PURE__ */ jsx76(Fragment14, { children: !selectedFile && !imagePreview ? /* @__PURE__ */ jsxs54(
14918
+ const dropZoneOrPreview = /* @__PURE__ */ jsx77(Fragment14, { children: !selectedFile && !imagePreview ? /* @__PURE__ */ jsxs55(
13896
14919
  "div",
13897
14920
  {
13898
14921
  ...getRootProps(),
@@ -13902,41 +14925,41 @@ var ITDropfile = ({
13902
14925
  ${isDragActive ? "border-primary-500 bg-primary-50 scale-[1.01]" : "border-secondary-300 bg-white hover:border-primary-400 hover:bg-secondary-50"}
13903
14926
  `,
13904
14927
  children: [
13905
- /* @__PURE__ */ jsx76("input", { ...getInputProps() }),
13906
- /* @__PURE__ */ jsx76("div", { className: `mb-3 p-3 rounded-full transition-colors duration-300 ${isDragActive ? "bg-primary-100" : "bg-secondary-100 group-hover:bg-primary-50"}`, children: /* @__PURE__ */ jsx76(
14928
+ /* @__PURE__ */ jsx77("input", { ...getInputProps() }),
14929
+ /* @__PURE__ */ jsx77("div", { className: `mb-3 p-3 rounded-full transition-colors duration-300 ${isDragActive ? "bg-primary-100" : "bg-secondary-100 group-hover:bg-primary-50"}`, children: /* @__PURE__ */ jsx77(
13907
14930
  "svg",
13908
14931
  {
13909
14932
  className: `w-6 h-6 transition-colors duration-300 ${isDragActive ? "text-primary-600" : "text-secondary-400 group-hover:text-primary-500"}`,
13910
14933
  fill: "none",
13911
14934
  viewBox: "0 0 24 24",
13912
14935
  stroke: "currentColor",
13913
- children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" })
14936
+ children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" })
13914
14937
  }
13915
14938
  ) }),
13916
- /* @__PURE__ */ jsx76("div", { className: "text-center space-y-1", children: /* @__PURE__ */ jsx76(ITText, { as: "p", className: `text-sm font-medium transition-colors duration-300 ${isDragActive ? "text-primary-700" : "text-secondary-700"}`, children: isDragActive ? t("dropfile.dropHere") : t("dropfile.clickOrDrag") }) })
14939
+ /* @__PURE__ */ jsx77("div", { className: "text-center space-y-1", children: /* @__PURE__ */ jsx77(ITText, { as: "p", className: `text-sm font-medium transition-colors duration-300 ${isDragActive ? "text-primary-700" : "text-secondary-700"}`, children: isDragActive ? t("dropfile.dropHere") : t("dropfile.clickOrDrag") }) })
13917
14940
  ]
13918
14941
  }
13919
- ) : /* @__PURE__ */ jsxs54("div", { className: "w-full bg-white border border-secondary-200 rounded-xl shadow-sm overflow-hidden animate-fade-in", children: [
13920
- /* @__PURE__ */ jsx76("div", { className: "flex items-center justify-between p-3 bg-secondary-50 border-b border-secondary-100", children: /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-3 overflow-hidden", children: [
13921
- /* @__PURE__ */ jsx76("div", { className: "flex-shrink-0 w-8 h-8 rounded-lg bg-primary-100 flex items-center justify-center text-primary-600", children: selectedFile && fileType?.startsWith("image/") || !selectedFile && imagePreview ? /* @__PURE__ */ jsx76("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) : /* @__PURE__ */ jsx76("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }),
13922
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0", children: [
13923
- /* @__PURE__ */ jsx76(ITText, { as: "p", className: "text-xs font-medium text-secondary-900 truncate", title: selectedFile?.name || t("dropfile.imageLoaded"), children: selectedFile?.name || t("dropfile.imageLoaded") }),
13924
- /* @__PURE__ */ jsx76(ITText, { as: "p", className: "text-[10px] text-secondary-500", children: selectedFile ? (selectedFile.size / 1024 / 1024).toFixed(2) + " MB" : "" })
14942
+ ) : /* @__PURE__ */ jsxs55("div", { className: "w-full bg-white border border-secondary-200 rounded-xl shadow-sm overflow-hidden animate-fade-in", children: [
14943
+ /* @__PURE__ */ jsx77("div", { className: "flex items-center justify-between p-3 bg-secondary-50 border-b border-secondary-100", children: /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-3 overflow-hidden", children: [
14944
+ /* @__PURE__ */ jsx77("div", { className: "flex-shrink-0 w-8 h-8 rounded-lg bg-primary-100 flex items-center justify-center text-primary-600", children: selectedFile && fileType?.startsWith("image/") || !selectedFile && imagePreview ? /* @__PURE__ */ jsx77("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) : /* @__PURE__ */ jsx77("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }),
14945
+ /* @__PURE__ */ jsxs55("div", { className: "min-w-0", children: [
14946
+ /* @__PURE__ */ jsx77(ITText, { as: "p", className: "text-xs font-medium text-secondary-900 truncate", title: selectedFile?.name || t("dropfile.imageLoaded"), children: selectedFile?.name || t("dropfile.imageLoaded") }),
14947
+ /* @__PURE__ */ jsx77(ITText, { as: "p", className: "text-[10px] text-secondary-500", children: selectedFile ? (selectedFile.size / 1024 / 1024).toFixed(2) + " MB" : "" })
13925
14948
  ] })
13926
14949
  ] }) }),
13927
- /* @__PURE__ */ jsx76("div", { className: clsx54("relative bg-secondary-100 flex items-center justify-center", !contentClassName ? "max-h-[200px] min-h-[100px] overflow-auto" : contentClassName), children: selectedFile && fileType?.startsWith("image/") || !selectedFile && imagePreview ? /* @__PURE__ */ jsx76(
14950
+ /* @__PURE__ */ jsx77("div", { className: clsx54("relative bg-secondary-100 flex items-center justify-center", !contentClassName ? "max-h-[200px] min-h-[100px] overflow-auto" : contentClassName), children: selectedFile && fileType?.startsWith("image/") || !selectedFile && imagePreview ? /* @__PURE__ */ jsx77(
13928
14951
  "img",
13929
14952
  {
13930
14953
  src: imagePreview,
13931
14954
  alt: t("dropfile.previewAlt"),
13932
14955
  className: "w-full h-full object-contain max-h-[200px]"
13933
14956
  }
13934
- ) : /* @__PURE__ */ jsxs54("div", { className: "py-8 flex flex-col items-center text-secondary-400", children: [
13935
- /* @__PURE__ */ jsx76("svg", { className: "w-10 h-10 mb-2 opacity-50", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
13936
- /* @__PURE__ */ jsx76(ITText, { as: "span", className: "text-xs", children: t("dropfile.noPreview") })
14957
+ ) : /* @__PURE__ */ jsxs55("div", { className: "py-8 flex flex-col items-center text-secondary-400", children: [
14958
+ /* @__PURE__ */ jsx77("svg", { className: "w-10 h-10 mb-2 opacity-50", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
14959
+ /* @__PURE__ */ jsx77(ITText, { as: "span", className: "text-xs", children: t("dropfile.noPreview") })
13937
14960
  ] }) }),
13938
- /* @__PURE__ */ jsx76("div", { className: "px-3 py-2 bg-white border-t border-secondary-100 flex justify-end gap-2", children: !isConfirmed ? /* @__PURE__ */ jsxs54(Fragment14, { children: [
13939
- /* @__PURE__ */ jsx76(
14961
+ /* @__PURE__ */ jsx77("div", { className: "px-3 py-2 bg-white border-t border-secondary-100 flex justify-end gap-2", children: !isConfirmed ? /* @__PURE__ */ jsxs55(Fragment14, { children: [
14962
+ /* @__PURE__ */ jsx77(
13940
14963
  ITButton,
13941
14964
  {
13942
14965
  type: "button",
@@ -13944,10 +14967,10 @@ var ITDropfile = ({
13944
14967
  color: "secondary",
13945
14968
  size: "sm",
13946
14969
  onClick: handleCancel,
13947
- children: /* @__PURE__ */ jsx76(ITText, { children: t("common.cancel") })
14970
+ children: /* @__PURE__ */ jsx77(ITText, { children: t("common.cancel") })
13948
14971
  }
13949
14972
  ),
13950
- /* @__PURE__ */ jsx76(
14973
+ /* @__PURE__ */ jsx77(
13951
14974
  ITButton,
13952
14975
  {
13953
14976
  type: "button",
@@ -13955,13 +14978,13 @@ var ITDropfile = ({
13955
14978
  color: "primary",
13956
14979
  size: "sm",
13957
14980
  onClick: handleConfirm,
13958
- children: /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-2", children: [
13959
- /* @__PURE__ */ jsx76(ITText, { children: t("common.confirm") }),
13960
- /* @__PURE__ */ jsx76("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) })
14981
+ children: /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
14982
+ /* @__PURE__ */ jsx77(ITText, { children: t("common.confirm") }),
14983
+ /* @__PURE__ */ jsx77("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) })
13961
14984
  ] })
13962
14985
  }
13963
14986
  )
13964
- ] }) : /* @__PURE__ */ jsxs54(
14987
+ ] }) : /* @__PURE__ */ jsxs55(
13965
14988
  ITButton,
13966
14989
  {
13967
14990
  type: "button",
@@ -13970,12 +14993,12 @@ var ITDropfile = ({
13970
14993
  size: "sm",
13971
14994
  onClick: handleDelete,
13972
14995
  children: [
13973
- /* @__PURE__ */ jsx76("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
13974
- /* @__PURE__ */ jsx76(ITText, { children: t("common.delete") })
14996
+ /* @__PURE__ */ jsx77("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
14997
+ /* @__PURE__ */ jsx77(ITText, { children: t("common.delete") })
13975
14998
  ]
13976
14999
  }
13977
15000
  ) }),
13978
- uploadStatus === "subiendo" /* UPLOADING */ && /* @__PURE__ */ jsx76("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx76("div", { className: "w-full bg-secondary-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx76(
15001
+ uploadStatus === "subiendo" /* UPLOADING */ && /* @__PURE__ */ jsx77("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx77("div", { className: "w-full bg-secondary-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx77(
13979
15002
  "div",
13980
15003
  {
13981
15004
  className: "bg-primary-600 h-1.5 rounded-full transition-all duration-1000 ease-out",
@@ -13988,8 +15011,8 @@ var ITDropfile = ({
13988
15011
  ] }) });
13989
15012
  if (view === "button") {
13990
15013
  const hasFile = Boolean(selectedFile || imagePreview);
13991
- return /* @__PURE__ */ jsxs54("div", { className: clsx54("inline-block", containerClassName), children: [
13992
- /* @__PURE__ */ jsx76(
15014
+ return /* @__PURE__ */ jsxs55("div", { className: clsx54("inline-block", containerClassName), children: [
15015
+ /* @__PURE__ */ jsx77(
13993
15016
  ITButton,
13994
15017
  {
13995
15018
  type: "button",
@@ -13997,20 +15020,20 @@ var ITDropfile = ({
13997
15020
  color: hasFile ? "primary" : "secondary",
13998
15021
  size: "sm",
13999
15022
  onClick: () => setIsModalOpen(true),
14000
- children: /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-2 max-w-[220px]", children: [
14001
- /* @__PURE__ */ jsx76("svg", { className: "w-4 h-4 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx76("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
14002
- /* @__PURE__ */ jsx76(ITText, { className: "truncate", children: selectedFile?.name || (hasFile ? t("dropfile.fileLoaded") : buttonLabel ?? t("dropfile.upload")) }),
14003
- showStatusBadge && hasFile && /* @__PURE__ */ jsx76(StatusBadge, { status: uploadStatus })
15023
+ children: /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 max-w-[220px]", children: [
15024
+ /* @__PURE__ */ jsx77("svg", { className: "w-4 h-4 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx77("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
15025
+ /* @__PURE__ */ jsx77(ITText, { className: "truncate", children: selectedFile?.name || (hasFile ? t("dropfile.fileLoaded") : buttonLabel ?? t("dropfile.upload")) }),
15026
+ showStatusBadge && hasFile && /* @__PURE__ */ jsx77(StatusBadge, { status: uploadStatus })
14004
15027
  ] })
14005
15028
  }
14006
15029
  ),
14007
- /* @__PURE__ */ jsx76(ITDialog, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), title: modalTitle ?? buttonLabel ?? t("dropfile.upload"), children: /* @__PURE__ */ jsxs54("div", { className: "w-full transition-all duration-300", children: [
15030
+ /* @__PURE__ */ jsx77(ITDialog, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), title: modalTitle ?? buttonLabel ?? t("dropfile.upload"), children: /* @__PURE__ */ jsxs55("div", { className: "w-full transition-all duration-300", children: [
14008
15031
  headerRow,
14009
15032
  dropZoneOrPreview
14010
15033
  ] }) })
14011
15034
  ] });
14012
15035
  }
14013
- return /* @__PURE__ */ jsxs54("div", { className: clsx54("w-full transition-all duration-300", containerClassName), children: [
15036
+ return /* @__PURE__ */ jsxs55("div", { className: clsx54("w-full transition-all duration-300", containerClassName), children: [
14014
15037
  headerRow,
14015
15038
  dropZoneOrPreview
14016
15039
  ] });
@@ -14018,13 +15041,13 @@ var ITDropfile = ({
14018
15041
  var dropfile_default = ITDropfile;
14019
15042
 
14020
15043
  // src/components/templates/layout/layout.tsx
14021
- import { useState as useState39 } from "react";
15044
+ import { useState as useState42 } from "react";
14022
15045
  import clsx55 from "clsx";
14023
15046
 
14024
15047
  // src/components/organisms/topbar/topbar.tsx
14025
15048
  import { FaUserCircle as FaUserCircle2, FaBars } from "react-icons/fa";
14026
- import { useRef as useRef24, useState as useState38 } from "react";
14027
- import { jsx as jsx77, jsxs as jsxs55 } from "react/jsx-runtime";
15049
+ import { useRef as useRef24, useState as useState41 } from "react";
15050
+ import { jsx as jsx78, jsxs as jsxs56 } from "react/jsx-runtime";
14028
15051
  function ITTopBar({
14029
15052
  logo,
14030
15053
  logoText,
@@ -14041,10 +15064,10 @@ function ITTopBar({
14041
15064
  const flat = useITFlatAppearance();
14042
15065
  const { t } = useITTranslation();
14043
15066
  const initials = (userMenu?.userName ?? "").trim().split(/\s+/).slice(0, 2).map((word) => word.charAt(0).toUpperCase()).join("");
14044
- const [isUserMenuOpen, setIsUserMenuOpen] = useState38(false);
15067
+ const [isUserMenuOpen, setIsUserMenuOpen] = useState41(false);
14045
15068
  const userMenuRef = useRef24(null);
14046
15069
  useClickOutside_default(userMenuRef, () => setIsUserMenuOpen(false));
14047
- return /* @__PURE__ */ jsx77(
15070
+ return /* @__PURE__ */ jsx78(
14048
15071
  "header",
14049
15072
  {
14050
15073
  className: `sticky top-0 z-40 transition-all duration-300 ${flat ? "" : "backdrop-blur-md"}`,
@@ -14053,9 +15076,9 @@ function ITTopBar({
14053
15076
  borderBottom: "1px solid var(--it-topbar-border, rgba(15, 23, 42, 0.06))",
14054
15077
  boxShadow: flat ? "none" : "var(--shadow-xs)"
14055
15078
  },
14056
- children: /* @__PURE__ */ jsxs55("div", { className: `flex items-center justify-between px-6 lg:px-8 ${flat ? "h-[64px]" : "h-[72px]"}`, children: [
14057
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-5", children: [
14058
- showMobileMenuButton && /* @__PURE__ */ jsx77(
15079
+ children: /* @__PURE__ */ jsxs56("div", { className: `flex items-center justify-between px-6 lg:px-8 ${flat ? "h-[64px]" : "h-[72px]"}`, children: [
15080
+ /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-5", children: [
15081
+ showMobileMenuButton && /* @__PURE__ */ jsx78(
14059
15082
  "button",
14060
15083
  {
14061
15084
  type: "button",
@@ -14067,12 +15090,12 @@ function ITTopBar({
14067
15090
  onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--it-topbar-user-hover, #f1f5f9)",
14068
15091
  onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
14069
15092
  onClick: onToggleMobileMenu,
14070
- children: /* @__PURE__ */ jsx77(FaBars, { className: "w-[1.125rem] h-[1.125rem]" })
15093
+ children: /* @__PURE__ */ jsx78(FaBars, { className: "w-[1.125rem] h-[1.125rem]" })
14071
15094
  }
14072
15095
  ),
14073
- /* @__PURE__ */ jsxs55("div", { className: `items-center gap-3 ${hideBrandOnDesktop ? "flex lg:hidden" : "flex"}`, children: [
14074
- logo && /* @__PURE__ */ jsx77("div", { className: "flex-shrink-0 drop-shadow-sm", children: logo }),
14075
- logoText && /* @__PURE__ */ jsx77(
15096
+ /* @__PURE__ */ jsxs56("div", { className: `items-center gap-3 ${hideBrandOnDesktop ? "flex lg:hidden" : "flex"}`, children: [
15097
+ logo && /* @__PURE__ */ jsx78("div", { className: "flex-shrink-0 drop-shadow-sm", children: logo }),
15098
+ logoText && /* @__PURE__ */ jsx78(
14076
15099
  ITText,
14077
15100
  {
14078
15101
  as: "span",
@@ -14082,7 +15105,7 @@ function ITTopBar({
14082
15105
  }
14083
15106
  )
14084
15107
  ] }),
14085
- navItems && navItems.length > 0 && /* @__PURE__ */ jsx77("nav", { className: "hidden md:flex ml-8 space-x-1 border-l pl-8", style: { borderColor: "var(--it-topbar-border, rgba(15, 23, 42, 0.06))" }, children: navItems.map((item) => /* @__PURE__ */ jsx77(
15108
+ navItems && navItems.length > 0 && /* @__PURE__ */ jsx78("nav", { className: "hidden md:flex ml-8 space-x-1 border-l pl-8", style: { borderColor: "var(--it-topbar-border, rgba(15, 23, 42, 0.06))" }, children: navItems.map((item) => /* @__PURE__ */ jsx78(
14086
15109
  "button",
14087
15110
  {
14088
15111
  onClick: () => onNavItemClick?.(item.id),
@@ -14096,19 +15119,19 @@ function ITTopBar({
14096
15119
  e.currentTarget.style.color = "var(--it-topbar-text, #475569)";
14097
15120
  e.currentTarget.style.backgroundColor = "transparent";
14098
15121
  },
14099
- children: /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
14100
- item.icon && /* @__PURE__ */ jsx77("span", { className: "opacity-70", children: item.icon }),
14101
- /* @__PURE__ */ jsx77(ITText, { as: "span", children: item.label })
15122
+ children: /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
15123
+ item.icon && /* @__PURE__ */ jsx78("span", { className: "opacity-70", children: item.icon }),
15124
+ /* @__PURE__ */ jsx78(ITText, { as: "span", children: item.label })
14102
15125
  ] })
14103
15126
  },
14104
15127
  item.id
14105
15128
  )) })
14106
15129
  ] }),
14107
- centerContent && /* @__PURE__ */ jsx77("div", { className: `hidden lg:flex flex-1 min-w-0 items-center ${hideBrandOnDesktop ? "justify-start pr-4" : "justify-center px-4"}`, children: /* @__PURE__ */ jsx77("div", { className: "w-full max-w-[420px]", children: centerContent }) }),
14108
- (children || userMenu) && /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
15130
+ centerContent && /* @__PURE__ */ jsx78("div", { className: `hidden lg:flex flex-1 min-w-0 items-center ${hideBrandOnDesktop ? "justify-start pr-4" : "justify-center px-4"}`, children: /* @__PURE__ */ jsx78("div", { className: "w-full max-w-[420px]", children: centerContent }) }),
15131
+ (children || userMenu) && /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
14109
15132
  children,
14110
- userMenu && /* @__PURE__ */ jsxs55("div", { className: "relative", children: [
14111
- /* @__PURE__ */ jsxs55(
15133
+ userMenu && /* @__PURE__ */ jsxs56("div", { className: "relative", children: [
15134
+ /* @__PURE__ */ jsxs56(
14112
15135
  "button",
14113
15136
  {
14114
15137
  type: "button",
@@ -14124,15 +15147,15 @@ function ITTopBar({
14124
15147
  },
14125
15148
  onClick: () => setIsUserMenuOpen(!isUserMenuOpen),
14126
15149
  children: [
14127
- /* @__PURE__ */ jsxs55("div", { className: "relative", children: [
14128
- userMenu.userImage ? /* @__PURE__ */ jsx77(
15150
+ /* @__PURE__ */ jsxs56("div", { className: "relative", children: [
15151
+ userMenu.userImage ? /* @__PURE__ */ jsx78(
14129
15152
  "img",
14130
15153
  {
14131
15154
  className: "w-9 h-9 rounded-full object-cover ring-2 ring-white shadow-sm",
14132
15155
  src: userMenu.userImage,
14133
15156
  alt: t("common.userAvatar")
14134
15157
  }
14135
- ) : flat && initials ? /* @__PURE__ */ jsx77(
15158
+ ) : flat && initials ? /* @__PURE__ */ jsx78(
14136
15159
  "div",
14137
15160
  {
14138
15161
  "aria-hidden": "true",
@@ -14143,11 +15166,11 @@ function ITTopBar({
14143
15166
  },
14144
15167
  children: initials
14145
15168
  }
14146
- ) : /* @__PURE__ */ jsx77("div", { className: "w-9 h-9 rounded-full bg-slate-100 flex items-center justify-center ring-2 ring-white shadow-sm", children: /* @__PURE__ */ jsx77(FaUserCircle2, { className: "w-6 h-6", style: { color: "var(--it-topbar-icon, #94a3b8)" } }) }),
14147
- !flat && /* @__PURE__ */ jsx77("div", { className: "absolute bottom-0 right-0 w-2.5 h-2.5 bg-green-500 border-2 border-white rounded-full" })
15169
+ ) : /* @__PURE__ */ jsx78("div", { className: "w-9 h-9 rounded-full bg-slate-100 flex items-center justify-center ring-2 ring-white shadow-sm", children: /* @__PURE__ */ jsx78(FaUserCircle2, { className: "w-6 h-6", style: { color: "var(--it-topbar-icon, #94a3b8)" } }) }),
15170
+ !flat && /* @__PURE__ */ jsx78("div", { className: "absolute bottom-0 right-0 w-2.5 h-2.5 bg-green-500 border-2 border-white rounded-full" })
14148
15171
  ] }),
14149
- /* @__PURE__ */ jsxs55("div", { className: `hidden sm:flex flex-col py-0.5 ${flat ? "text-right" : "text-left"}`, children: [
14150
- /* @__PURE__ */ jsx77(
15172
+ /* @__PURE__ */ jsxs56("div", { className: `hidden sm:flex flex-col py-0.5 ${flat ? "text-right" : "text-left"}`, children: [
15173
+ /* @__PURE__ */ jsx78(
14151
15174
  ITText,
14152
15175
  {
14153
15176
  as: "span",
@@ -14156,7 +15179,7 @@ function ITTopBar({
14156
15179
  children: userMenu.userName
14157
15180
  }
14158
15181
  ),
14159
- /* @__PURE__ */ jsx77(
15182
+ /* @__PURE__ */ jsx78(
14160
15183
  ITText,
14161
15184
  {
14162
15185
  as: "span",
@@ -14169,7 +15192,7 @@ function ITTopBar({
14169
15192
  ]
14170
15193
  }
14171
15194
  ),
14172
- /* @__PURE__ */ jsxs55(
15195
+ /* @__PURE__ */ jsxs56(
14173
15196
  "div",
14174
15197
  {
14175
15198
  ref: userMenuRef,
@@ -14182,15 +15205,15 @@ function ITTopBar({
14182
15205
  border: "1px solid var(--it-topbar-user-dropdown-border, #f1f5f9)"
14183
15206
  },
14184
15207
  children: [
14185
- /* @__PURE__ */ jsxs55("div", { className: "px-5 py-4 border-b", style: { borderColor: "var(--it-topbar-user-dropdown-border, #f1f5f9)", backgroundColor: "var(--it-topbar-user-bg, #f8fafc)" }, children: [
14186
- /* @__PURE__ */ jsx77(ITText, { as: "span", className: "block font-bold text-[0.9rem]", style: { color: "var(--it-topbar-user-text, #0f172a)" }, children: userMenu.userName }),
14187
- /* @__PURE__ */ jsx77(ITText, { as: "span", className: "block text-xs font-medium truncate mt-0.5", style: { color: "var(--it-topbar-user-subtitle, #64748b)" }, children: userMenu.userEmail })
15208
+ /* @__PURE__ */ jsxs56("div", { className: "px-5 py-4 border-b", style: { borderColor: "var(--it-topbar-user-dropdown-border, #f1f5f9)", backgroundColor: "var(--it-topbar-user-bg, #f8fafc)" }, children: [
15209
+ /* @__PURE__ */ jsx78(ITText, { as: "span", className: "block font-bold text-[0.9rem]", style: { color: "var(--it-topbar-user-text, #0f172a)" }, children: userMenu.userName }),
15210
+ /* @__PURE__ */ jsx78(ITText, { as: "span", className: "block text-xs font-medium truncate mt-0.5", style: { color: "var(--it-topbar-user-subtitle, #64748b)" }, children: userMenu.userEmail })
14188
15211
  ] }),
14189
- /* @__PURE__ */ jsx77("ul", { className: "py-2", children: userMenu.menuItems.map((m, i) => {
15212
+ /* @__PURE__ */ jsx78("ul", { className: "py-2", children: userMenu.menuItems.map((m, i) => {
14190
15213
  const isDestructive = m.label.toLowerCase().includes("salir") || m.label.toLowerCase().includes("cerrar") || m.label.toLowerCase().includes("logout");
14191
- return /* @__PURE__ */ jsxs55("li", { className: "px-2", children: [
14192
- i === userMenu.menuItems.length - 1 && isDestructive && i > 0 && /* @__PURE__ */ jsx77("div", { className: "h-px bg-slate-100 my-1 mx-2" }),
14193
- /* @__PURE__ */ jsx77(
15214
+ return /* @__PURE__ */ jsxs56("li", { className: "px-2", children: [
15215
+ i === userMenu.menuItems.length - 1 && isDestructive && i > 0 && /* @__PURE__ */ jsx78("div", { className: "h-px bg-slate-100 my-1 mx-2" }),
15216
+ /* @__PURE__ */ jsx78(
14194
15217
  "button",
14195
15218
  {
14196
15219
  onClick: () => {
@@ -14205,7 +15228,7 @@ function ITTopBar({
14205
15228
  onMouseLeave: (e) => {
14206
15229
  e.currentTarget.style.backgroundColor = "transparent";
14207
15230
  },
14208
- children: /* @__PURE__ */ jsx77(ITText, { as: "span", children: m.label })
15231
+ children: /* @__PURE__ */ jsx78(ITText, { as: "span", children: m.label })
14209
15232
  }
14210
15233
  )
14211
15234
  ] }, i);
@@ -14221,7 +15244,7 @@ function ITTopBar({
14221
15244
  }
14222
15245
 
14223
15246
  // src/components/templates/layout/layout.tsx
14224
- import { jsx as jsx78, jsxs as jsxs56 } from "react/jsx-runtime";
15247
+ import { jsx as jsx79, jsxs as jsxs57 } from "react/jsx-runtime";
14225
15248
  function ITLayout({
14226
15249
  topBar,
14227
15250
  sidebar,
@@ -14230,8 +15253,8 @@ function ITLayout({
14230
15253
  contentClassName = "",
14231
15254
  sidebarFullHeight = false
14232
15255
  }) {
14233
- const [internalCollapsed, setInternalCollapsed] = useState39(true);
14234
- const [mobileSidebarOpen, setMobileSidebarOpen] = useState39(false);
15256
+ const [internalCollapsed, setInternalCollapsed] = useState42(true);
15257
+ const [mobileSidebarOpen, setMobileSidebarOpen] = useState42(false);
14235
15258
  const flat = useITFlatAppearance();
14236
15259
  const isControlled = sidebar.isCollapsed !== void 0;
14237
15260
  const desktopCollapsed = isControlled ? sidebar.isCollapsed : internalCollapsed;
@@ -14245,7 +15268,7 @@ function ITLayout({
14245
15268
  else setMobileSidebarOpen((v) => !v);
14246
15269
  };
14247
15270
  const brand = sidebarFullHeight ? sidebar.brand ?? { logo: topBar.logo, text: topBar.logoText } : sidebar.brand;
14248
- const topBarNode = /* @__PURE__ */ jsx78(
15271
+ const topBarNode = /* @__PURE__ */ jsx79(
14249
15272
  ITTopBar,
14250
15273
  {
14251
15274
  ...topBar,
@@ -14258,9 +15281,9 @@ function ITLayout({
14258
15281
  const desktopSidebar = (
14259
15282
  // Full-height: the sidebar sits beside the top bar, so it needs to win the
14260
15283
  // stacking order when the collapsed rail expands over the content on hover.
14261
- /* @__PURE__ */ jsxs56("div", { className: `hidden lg:block relative h-full ${sidebarFullHeight ? "z-50" : "z-40"}`, children: [
14262
- /* @__PURE__ */ jsx78("div", { className: `${reservedWidth} h-full flex-shrink-0` }),
14263
- /* @__PURE__ */ jsx78("div", { className: "absolute top-0 left-0 h-full", children: /* @__PURE__ */ jsx78(
15284
+ /* @__PURE__ */ jsxs57("div", { className: `hidden lg:block relative h-full ${sidebarFullHeight ? "z-50" : "z-40"}`, children: [
15285
+ /* @__PURE__ */ jsx79("div", { className: `${reservedWidth} h-full flex-shrink-0` }),
15286
+ /* @__PURE__ */ jsx79("div", { className: "absolute top-0 left-0 h-full", children: /* @__PURE__ */ jsx79(
14264
15287
  ITSidebar,
14265
15288
  {
14266
15289
  ...sidebar,
@@ -14273,17 +15296,17 @@ function ITLayout({
14273
15296
  ) })
14274
15297
  ] })
14275
15298
  );
14276
- const mobileSidebar = mobileSidebarOpen && /* @__PURE__ */ jsx78(
15299
+ const mobileSidebar = mobileSidebarOpen && /* @__PURE__ */ jsx79(
14277
15300
  "div",
14278
15301
  {
14279
15302
  className: "lg:hidden fixed inset-0 z-[40] transition-opacity duration-300 backdrop-blur-sm bg-black/40",
14280
15303
  onClick: () => setMobileSidebarOpen(false),
14281
- children: /* @__PURE__ */ jsx78(
15304
+ children: /* @__PURE__ */ jsx79(
14282
15305
  "div",
14283
15306
  {
14284
15307
  className: "h-full w-fit flex transform transition-transform duration-300 ease-[cubic-bezier(0.2,0,0,1)]",
14285
15308
  onClick: (e) => e.stopPropagation(),
14286
- children: /* @__PURE__ */ jsx78(
15309
+ children: /* @__PURE__ */ jsx79(
14287
15310
  ITSidebar,
14288
15311
  {
14289
15312
  ...sidebar,
@@ -14300,16 +15323,16 @@ function ITLayout({
14300
15323
  )
14301
15324
  }
14302
15325
  );
14303
- const main = /* @__PURE__ */ jsx78("main", { className: "flex-1 overflow-y-auto w-full custom-scrollbar relative z-0", children: /* @__PURE__ */ jsx78("div", { className: clsx55("mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-6 h-full", contentClassName), children }) });
15326
+ const main = /* @__PURE__ */ jsx79("main", { className: "flex-1 overflow-y-auto w-full custom-scrollbar relative z-0", children: /* @__PURE__ */ jsx79("div", { className: clsx55("mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-6 h-full", contentClassName), children }) });
14304
15327
  if (sidebarFullHeight) {
14305
- return /* @__PURE__ */ jsxs56(
15328
+ return /* @__PURE__ */ jsxs57(
14306
15329
  "div",
14307
15330
  {
14308
15331
  className: `flex h-screen overflow-hidden w-full relative ${className}`,
14309
15332
  style: { backgroundColor: layoutTokens.backgroundColor },
14310
15333
  children: [
14311
15334
  desktopSidebar,
14312
- /* @__PURE__ */ jsxs56("div", { className: "flex flex-col flex-1 min-w-0 overflow-hidden", children: [
15335
+ /* @__PURE__ */ jsxs57("div", { className: "flex flex-col flex-1 min-w-0 overflow-hidden", children: [
14313
15336
  topBarNode,
14314
15337
  main
14315
15338
  ] }),
@@ -14318,9 +15341,9 @@ function ITLayout({
14318
15341
  }
14319
15342
  );
14320
15343
  }
14321
- return /* @__PURE__ */ jsxs56("div", { className: `flex flex-col h-screen overflow-hidden w-full ${className}`, children: [
15344
+ return /* @__PURE__ */ jsxs57("div", { className: `flex flex-col h-screen overflow-hidden w-full ${className}`, children: [
14322
15345
  topBarNode,
14323
- /* @__PURE__ */ jsxs56(
15346
+ /* @__PURE__ */ jsxs57(
14324
15347
  "div",
14325
15348
  {
14326
15349
  className: "flex flex-1 overflow-hidden relative",
@@ -14337,9 +15360,9 @@ function ITLayout({
14337
15360
 
14338
15361
  // src/components/molecules/stepper/stepper.tsx
14339
15362
  import clsx56 from "clsx";
14340
- import { useEffect as useEffect20, useRef as useRef25, useState as useState40 } from "react";
15363
+ import { useEffect as useEffect21, useRef as useRef25, useState as useState43 } from "react";
14341
15364
  import { FaChevronLeft as FaChevronLeft4, FaChevronRight as FaChevronRight7, FaCheck as FaCheck6 } from "react-icons/fa";
14342
- import { jsx as jsx79, jsxs as jsxs57 } from "react/jsx-runtime";
15365
+ import { jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
14343
15366
  function ITStepper({
14344
15367
  steps,
14345
15368
  currentStep,
@@ -14355,15 +15378,15 @@ function ITStepper({
14355
15378
  color = "primary"
14356
15379
  }) {
14357
15380
  const { t } = useITTranslation();
14358
- const [direction, setDirection] = useState40("next");
15381
+ const [direction, setDirection] = useState43("next");
14359
15382
  const contentRef = useRef25(null);
14360
15383
  const progressRef = useRef25(null);
14361
15384
  const isThemeColor = color in theme.colors;
14362
15385
  const resolvedColor = isThemeColor ? theme.colors[color][500] : color;
14363
- useEffect20(() => {
15386
+ useEffect21(() => {
14364
15387
  onStepChange?.(currentStep);
14365
15388
  }, [currentStep, onStepChange]);
14366
- useEffect20(() => {
15389
+ useEffect21(() => {
14367
15390
  const pct = currentStep / Math.max(1, steps.length - 1) * 100;
14368
15391
  if (progressRef.current) {
14369
15392
  progressRef.current.style.width = `${pct}%`;
@@ -14407,23 +15430,23 @@ function ITStepper({
14407
15430
  const renderStepContent = (index, isCompleted) => {
14408
15431
  const step = steps[index];
14409
15432
  if (isCompleted) {
14410
- return /* @__PURE__ */ jsx79(FaCheck6, { className: "w-4 h-4" });
15433
+ return /* @__PURE__ */ jsx80(FaCheck6, { className: "w-4 h-4" });
14411
15434
  }
14412
15435
  if (step.icon && useIcons) {
14413
- return /* @__PURE__ */ jsx79("div", { className: "flex items-center justify-center w-5 h-5", children: step.icon });
15436
+ return /* @__PURE__ */ jsx80("div", { className: "flex items-center justify-center w-5 h-5", children: step.icon });
14414
15437
  }
14415
- return /* @__PURE__ */ jsx79(ITText, { as: "span", className: "text-sm font-semibold", children: index + 1 });
15438
+ return /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-sm font-semibold", children: index + 1 });
14416
15439
  };
14417
- return /* @__PURE__ */ jsxs57("div", { className: clsx56("w-full max-w-5xl mx-auto px-4", containerClassName), children: [
14418
- /* @__PURE__ */ jsxs57("div", { className: "relative mb-8", children: [
14419
- /* @__PURE__ */ jsx79(
15440
+ return /* @__PURE__ */ jsxs58("div", { className: clsx56("w-full max-w-5xl mx-auto px-4", containerClassName), children: [
15441
+ /* @__PURE__ */ jsxs58("div", { className: "relative mb-8", children: [
15442
+ /* @__PURE__ */ jsx80(
14420
15443
  "div",
14421
15444
  {
14422
15445
  className: "absolute left-6 right-6 top-5 h-1 bg-secondary-200 rounded-full z-0",
14423
15446
  "aria-hidden": true
14424
15447
  }
14425
15448
  ),
14426
- /* @__PURE__ */ jsx79(
15449
+ /* @__PURE__ */ jsx80(
14427
15450
  "div",
14428
15451
  {
14429
15452
  ref: progressRef,
@@ -14431,11 +15454,11 @@ function ITStepper({
14431
15454
  "aria-hidden": true
14432
15455
  }
14433
15456
  ),
14434
- /* @__PURE__ */ jsx79("div", { className: "flex items-start justify-between space-x-2 relative z-20", children: steps.map((step, idx) => {
15457
+ /* @__PURE__ */ jsx80("div", { className: "flex items-start justify-between space-x-2 relative z-20", children: steps.map((step, idx) => {
14435
15458
  const isActive = idx === currentStep;
14436
15459
  const isCompleted = idx < currentStep;
14437
15460
  const hasIcon = step.icon && useIcons;
14438
- return /* @__PURE__ */ jsx79(
15461
+ return /* @__PURE__ */ jsx80(
14439
15462
  "button",
14440
15463
  {
14441
15464
  type: "button",
@@ -14445,8 +15468,8 @@ function ITStepper({
14445
15468
  "aria-label": t("stepper.stepAria", { n: idx + 1, label: step.label }),
14446
15469
  className: "flex-1 group",
14447
15470
  title: step.label,
14448
- children: /* @__PURE__ */ jsxs57("div", { className: "flex flex-col items-center", children: [
14449
- /* @__PURE__ */ jsx79(
15471
+ children: /* @__PURE__ */ jsxs58("div", { className: "flex flex-col items-center", children: [
15472
+ /* @__PURE__ */ jsx80(
14450
15473
  "div",
14451
15474
  {
14452
15475
  className: clsx56(
@@ -14460,7 +15483,7 @@ function ITStepper({
14460
15483
  children: renderStepContent(idx, isCompleted)
14461
15484
  }
14462
15485
  ),
14463
- /* @__PURE__ */ jsx79(
15486
+ /* @__PURE__ */ jsx80(
14464
15487
  ITText,
14465
15488
  {
14466
15489
  as: "span",
@@ -14478,7 +15501,7 @@ function ITStepper({
14478
15501
  );
14479
15502
  }) })
14480
15503
  ] }),
14481
- /* @__PURE__ */ jsx79(
15504
+ /* @__PURE__ */ jsx80(
14482
15505
  "div",
14483
15506
  {
14484
15507
  ref: contentRef,
@@ -14494,32 +15517,32 @@ function ITStepper({
14494
15517
  children: steps[currentStep].content
14495
15518
  }
14496
15519
  ),
14497
- /* @__PURE__ */ jsxs57("div", { className: "flex justify-between items-center mt-6", children: [
14498
- /* @__PURE__ */ jsx79(
15520
+ /* @__PURE__ */ jsxs58("div", { className: "flex justify-between items-center mt-6", children: [
15521
+ /* @__PURE__ */ jsx80(
14499
15522
  ITButton,
14500
15523
  {
14501
15524
  variant: "outlined",
14502
15525
  color: "secondary",
14503
15526
  disabled: currentStep === 0,
14504
15527
  onClick: prevStep,
14505
- children: /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
14506
- /* @__PURE__ */ jsx79(FaChevronLeft4, {}),
14507
- /* @__PURE__ */ jsx79(ITText, { as: "span", children: t("common.back") })
15528
+ children: /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-2", children: [
15529
+ /* @__PURE__ */ jsx80(FaChevronLeft4, {}),
15530
+ /* @__PURE__ */ jsx80(ITText, { as: "span", children: t("common.back") })
14508
15531
  ] })
14509
15532
  }
14510
15533
  ),
14511
- /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-3", children: [
14512
- /* @__PURE__ */ jsx79(ITText, { as: "div", className: "text-sm text-secondary-500 mr-2 hidden sm:block", children: t("stepper.stepOf", { current: currentStep + 1, total: steps.length }) }),
14513
- /* @__PURE__ */ jsx79(
15534
+ /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-3", children: [
15535
+ /* @__PURE__ */ jsx80(ITText, { as: "div", className: "text-sm text-secondary-500 mr-2 hidden sm:block", children: t("stepper.stepOf", { current: currentStep + 1, total: steps.length }) }),
15536
+ /* @__PURE__ */ jsx80(
14514
15537
  ITButton,
14515
15538
  {
14516
15539
  variant: "solid",
14517
15540
  color,
14518
15541
  disabled: disableNext,
14519
15542
  onClick: nextStep,
14520
- children: /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
14521
- /* @__PURE__ */ jsx79(ITText, { as: "span", children: currentStep === steps.length - 1 ? t("common.finish") : t("common.next") }),
14522
- currentStep === steps.length - 1 ? /* @__PURE__ */ jsx79(FaCheck6, {}) : /* @__PURE__ */ jsx79(FaChevronRight7, {})
15543
+ children: /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-2", children: [
15544
+ /* @__PURE__ */ jsx80(ITText, { as: "span", children: currentStep === steps.length - 1 ? t("common.finish") : t("common.next") }),
15545
+ currentStep === steps.length - 1 ? /* @__PURE__ */ jsx80(FaCheck6, {}) : /* @__PURE__ */ jsx80(FaChevronRight7, {})
14523
15546
  ] })
14524
15547
  }
14525
15548
  )
@@ -14529,7 +15552,7 @@ function ITStepper({
14529
15552
  }
14530
15553
 
14531
15554
  // src/components/theme-provider/themeProvider.tsx
14532
- import { useState as useState41, useEffect as useEffect21, useLayoutEffect as useLayoutEffect5 } from "react";
15555
+ import { useState as useState44, useEffect as useEffect22, useLayoutEffect as useLayoutEffect5 } from "react";
14533
15556
  import { MdPalette, MdClose, MdRefresh } from "react-icons/md";
14534
15557
 
14535
15558
  // src/components/theme-provider/themePresets.ts
@@ -14707,7 +15730,7 @@ var PRESETS = [
14707
15730
  ];
14708
15731
 
14709
15732
  // src/components/theme-provider/themeProvider.tsx
14710
- import { jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
15733
+ import { jsx as jsx81, jsxs as jsxs59 } from "react/jsx-runtime";
14711
15734
  var STORAGE_KEY = "it-theme-palette";
14712
15735
  var SHADOW_LEVELS = {
14713
15736
  0: {
@@ -14810,7 +15833,7 @@ function ITThemeProvider({
14810
15833
  appearance = "soft"
14811
15834
  }) {
14812
15835
  const { t } = useITTranslation();
14813
- const [palette2, setPaletteState] = useState41(() => {
15836
+ const [palette2, setPaletteState] = useState44(() => {
14814
15837
  const basePalette = {
14815
15838
  ...DEFAULT_PALETTE,
14816
15839
  ...theme2,
@@ -14836,8 +15859,8 @@ function ITThemeProvider({
14836
15859
  }
14837
15860
  return basePalette;
14838
15861
  });
14839
- const [isOpen, setIsOpen] = useState41(false);
14840
- const [customPresets, setCustomPresets] = useState41(() => {
15862
+ const [isOpen, setIsOpen] = useState44(false);
15863
+ const [customPresets, setCustomPresets] = useState44(() => {
14841
15864
  try {
14842
15865
  const saved = localStorage.getItem("it-theme-custom-presets");
14843
15866
  return saved ? JSON.parse(saved) : [];
@@ -14846,8 +15869,8 @@ function ITThemeProvider({
14846
15869
  return [];
14847
15870
  }
14848
15871
  });
14849
- const [newPresetName, setNewPresetName] = useState41("");
14850
- const [isSavingPreset, setIsSavingPreset] = useState41(false);
15872
+ const [newPresetName, setNewPresetName] = useState44("");
15873
+ const [isSavingPreset, setIsSavingPreset] = useState44(false);
14851
15874
  const handleSavePreset = () => {
14852
15875
  if (!newPresetName.trim()) return;
14853
15876
  const newPreset = {
@@ -14866,8 +15889,8 @@ function ITThemeProvider({
14866
15889
  setCustomPresets(updated);
14867
15890
  localStorage.setItem("it-theme-custom-presets", JSON.stringify(updated));
14868
15891
  };
14869
- const [resolvedTheme, setResolvedTheme] = useState41("light");
14870
- const [darkModeMode, setDarkModeMode] = useState41(
15892
+ const [resolvedTheme, setResolvedTheme] = useState44("light");
15893
+ const [darkModeMode, setDarkModeMode] = useState44(
14871
15894
  () => {
14872
15895
  const saved = localStorage.getItem("it-theme-dark-mode");
14873
15896
  if (saved === "light" || saved === "dark" || saved === "system") {
@@ -14876,7 +15899,7 @@ function ITThemeProvider({
14876
15899
  return "system";
14877
15900
  }
14878
15901
  );
14879
- useEffect21(() => {
15902
+ useEffect22(() => {
14880
15903
  localStorage.setItem("it-theme-dark-mode", darkModeMode);
14881
15904
  const applyDarkMode = (isDark) => {
14882
15905
  if (isDark) {
@@ -14901,7 +15924,7 @@ function ITThemeProvider({
14901
15924
  applyDarkMode(darkModeMode === "dark");
14902
15925
  }
14903
15926
  }, [darkModeMode]);
14904
- useEffect21(() => {
15927
+ useEffect22(() => {
14905
15928
  if (!showFab) {
14906
15929
  setPaletteState({
14907
15930
  ...DEFAULT_PALETTE,
@@ -14958,7 +15981,7 @@ function ITThemeProvider({
14958
15981
  surfaceStyle?.remove();
14959
15982
  };
14960
15983
  }, [radius, shadow]);
14961
- useEffect21(() => {
15984
+ useEffect22(() => {
14962
15985
  const injectStyles = (obj, prefix = "") => {
14963
15986
  Object.entries(obj).forEach(([key, val]) => {
14964
15987
  if (typeof val === "object" && val !== null) {
@@ -16112,14 +17135,14 @@ function ITThemeProvider({
16112
17135
  const isNested = colorKey.includes(".");
16113
17136
  const label = isNested ? colorKey.split(".")[1] : colorKey;
16114
17137
  const value = getNestedValue3(palette2, colorKey);
16115
- return /* @__PURE__ */ jsxs58(
17138
+ return /* @__PURE__ */ jsxs59(
16116
17139
  "div",
16117
17140
  {
16118
17141
  className: "flex items-center justify-between p-3 rounded-xl border border-slate-100 dark:border-slate-800 bg-white dark:bg-slate-900/50 gap-3 hover:border-slate-200 dark:hover:border-slate-700 transition-colors",
16119
17142
  children: [
16120
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [
16121
- /* @__PURE__ */ jsxs58("div", { className: "relative w-10 h-10 rounded-xl border-2 border-slate-200 dark:border-slate-700 overflow-hidden cursor-pointer flex-shrink-0 shadow-sm hover:scale-105 transition-transform", children: [
16122
- /* @__PURE__ */ jsx80(
17143
+ /* @__PURE__ */ jsxs59("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [
17144
+ /* @__PURE__ */ jsxs59("div", { className: "relative w-10 h-10 rounded-xl border-2 border-slate-200 dark:border-slate-700 overflow-hidden cursor-pointer flex-shrink-0 shadow-sm hover:scale-105 transition-transform", children: [
17145
+ /* @__PURE__ */ jsx81(
16123
17146
  "input",
16124
17147
  {
16125
17148
  type: "color",
@@ -16128,23 +17151,23 @@ function ITThemeProvider({
16128
17151
  className: "absolute inset-0 opacity-0 cursor-pointer w-full h-full"
16129
17152
  }
16130
17153
  ),
16131
- /* @__PURE__ */ jsx80("div", { className: "w-full h-full", style: { backgroundColor: value } })
17154
+ /* @__PURE__ */ jsx81("div", { className: "w-full h-full", style: { backgroundColor: value } })
16132
17155
  ] }),
16133
- /* @__PURE__ */ jsxs58("div", { className: "flex flex-col min-w-0", children: [
16134
- /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-xs font-bold text-slate-700 dark:text-slate-300 truncate capitalize", children: label.replace(/([A-Z])/g, " $1").trim() }),
16135
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-2 mt-0.5", children: [
16136
- /* @__PURE__ */ jsx80(
17156
+ /* @__PURE__ */ jsxs59("div", { className: "flex flex-col min-w-0", children: [
17157
+ /* @__PURE__ */ jsx81(ITText, { as: "span", className: "text-xs font-bold text-slate-700 dark:text-slate-300 truncate capitalize", children: label.replace(/([A-Z])/g, " $1").trim() }),
17158
+ /* @__PURE__ */ jsxs59("div", { className: "flex items-center gap-2 mt-0.5", children: [
17159
+ /* @__PURE__ */ jsx81(
16137
17160
  "span",
16138
17161
  {
16139
17162
  className: "w-3 h-3 rounded-full border border-slate-200 dark:border-slate-600",
16140
17163
  style: { backgroundColor: value }
16141
17164
  }
16142
17165
  ),
16143
- /* @__PURE__ */ jsx80(ITText, { as: "span", className: "font-mono text-[11px] text-slate-400", children: value })
17166
+ /* @__PURE__ */ jsx81(ITText, { as: "span", className: "font-mono text-[11px] text-slate-400", children: value })
16144
17167
  ] })
16145
17168
  ] })
16146
17169
  ] }),
16147
- /* @__PURE__ */ jsx80(
17170
+ /* @__PURE__ */ jsx81(
16148
17171
  "input",
16149
17172
  {
16150
17173
  type: "text",
@@ -16163,14 +17186,14 @@ function ITThemeProvider({
16163
17186
  isCustom
16164
17187
  }) => {
16165
17188
  const isSelected = JSON.stringify(preset.colors) === JSON.stringify(palette2);
16166
- return /* @__PURE__ */ jsxs58(
17189
+ return /* @__PURE__ */ jsxs59(
16167
17190
  "button",
16168
17191
  {
16169
17192
  type: "button",
16170
17193
  onClick: () => applyPreset(preset.colors),
16171
17194
  className: `relative flex flex-col items-start p-2.5 rounded-xl border text-left transition-all group ${isSelected ? "border-primary-500 bg-primary-500/5 shadow-sm ring-1 ring-primary-500/20" : "border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900/50 hover:border-slate-300 dark:hover:border-slate-600"}`,
16172
17195
  children: [
16173
- isCustom && /* @__PURE__ */ jsx80(
17196
+ isCustom && /* @__PURE__ */ jsx81(
16174
17197
  "span",
16175
17198
  {
16176
17199
  onClick: (e) => {
@@ -16179,11 +17202,11 @@ function ITThemeProvider({
16179
17202
  },
16180
17203
  className: "absolute top-1.5 right-1.5 opacity-0 group-hover:opacity-100 p-0.5 rounded-md hover:bg-danger-500/10 hover:text-danger-500 text-slate-400 dark:text-slate-500 cursor-pointer transition-all z-10",
16181
17204
  title: t("themeProvider.designer.deletePreset"),
16182
- children: /* @__PURE__ */ jsx80(MdClose, { size: 12 })
17205
+ children: /* @__PURE__ */ jsx81(MdClose, { size: 12 })
16183
17206
  }
16184
17207
  ),
16185
- /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-xs font-semibold truncate w-full mb-1.5 pr-4 text-slate-700 dark:text-slate-300", children: PRESET_I18N_KEY[preset.name] ? t(PRESET_I18N_KEY[preset.name]) : preset.name }),
16186
- /* @__PURE__ */ jsx80("div", { className: "flex gap-1", children: ["primary", "secondary", "ternary", "success"].map((c) => /* @__PURE__ */ jsx80(
17208
+ /* @__PURE__ */ jsx81(ITText, { as: "span", className: "text-xs font-semibold truncate w-full mb-1.5 pr-4 text-slate-700 dark:text-slate-300", children: PRESET_I18N_KEY[preset.name] ? t(PRESET_I18N_KEY[preset.name]) : preset.name }),
17209
+ /* @__PURE__ */ jsx81("div", { className: "flex gap-1", children: ["primary", "secondary", "ternary", "success"].map((c) => /* @__PURE__ */ jsx81(
16187
17210
  "span",
16188
17211
  {
16189
17212
  className: "w-3 h-3 rounded-full border border-black/10",
@@ -16195,7 +17218,7 @@ function ITThemeProvider({
16195
17218
  }
16196
17219
  );
16197
17220
  };
16198
- return /* @__PURE__ */ jsxs58(
17221
+ return /* @__PURE__ */ jsxs59(
16199
17222
  ITThemeContext.Provider,
16200
17223
  {
16201
17224
  value: {
@@ -16212,28 +17235,28 @@ function ITThemeProvider({
16212
17235
  },
16213
17236
  children: [
16214
17237
  children,
16215
- showFab && /* @__PURE__ */ jsx80(
17238
+ showFab && /* @__PURE__ */ jsx81(
16216
17239
  "button",
16217
17240
  {
16218
17241
  onClick: () => setIsOpen((prev) => !prev),
16219
17242
  className: "it-theme-fab it-theme-bounce",
16220
17243
  style: { backgroundColor: "var(--color-primary)" },
16221
17244
  "aria-label": t("themeProvider.fab.ariaLabel"),
16222
- children: /* @__PURE__ */ jsx80(MdPalette, { size: 28 })
17245
+ children: /* @__PURE__ */ jsx81(MdPalette, { size: 28 })
16223
17246
  }
16224
17247
  ),
16225
- showFab && /* @__PURE__ */ jsx80(
17248
+ showFab && /* @__PURE__ */ jsx81(
16226
17249
  ITDialog,
16227
17250
  {
16228
17251
  isOpen,
16229
17252
  onClose: () => setIsOpen(false),
16230
17253
  title: t("themeProvider.designer.title"),
16231
17254
  useFormHeader: true,
16232
- children: /* @__PURE__ */ jsxs58("div", { className: "flex gap-6 h-[580px]", children: [
16233
- /* @__PURE__ */ jsxs58("div", { className: "w-64 flex-shrink-0 flex flex-col gap-5 overflow-y-auto pr-1", children: [
16234
- /* @__PURE__ */ jsxs58("div", { children: [
16235
- /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block", children: t("themeProvider.designer.appearance") }),
16236
- /* @__PURE__ */ jsx80(
17255
+ children: /* @__PURE__ */ jsxs59("div", { className: "flex gap-6 h-[580px]", children: [
17256
+ /* @__PURE__ */ jsxs59("div", { className: "w-64 flex-shrink-0 flex flex-col gap-5 overflow-y-auto pr-1", children: [
17257
+ /* @__PURE__ */ jsxs59("div", { children: [
17258
+ /* @__PURE__ */ jsx81(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block", children: t("themeProvider.designer.appearance") }),
17259
+ /* @__PURE__ */ jsx81(
16237
17260
  ITSegmentedControl,
16238
17261
  {
16239
17262
  options: [
@@ -16247,16 +17270,16 @@ function ITThemeProvider({
16247
17270
  }
16248
17271
  )
16249
17272
  ] }),
16250
- /* @__PURE__ */ jsxs58("div", { children: [
16251
- /* @__PURE__ */ jsx80("div", { className: "flex items-center justify-between mb-2.5", children: /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500", children: t("themeProvider.designer.presets") }) }),
16252
- /* @__PURE__ */ jsx80("div", { className: "grid grid-cols-2 gap-2", children: PRESETS.map((preset) => /* @__PURE__ */ jsx80(PresetCard, { preset }, preset.name)) })
17273
+ /* @__PURE__ */ jsxs59("div", { children: [
17274
+ /* @__PURE__ */ jsx81("div", { className: "flex items-center justify-between mb-2.5", children: /* @__PURE__ */ jsx81(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500", children: t("themeProvider.designer.presets") }) }),
17275
+ /* @__PURE__ */ jsx81("div", { className: "grid grid-cols-2 gap-2", children: PRESETS.map((preset) => /* @__PURE__ */ jsx81(PresetCard, { preset }, preset.name)) })
16253
17276
  ] }),
16254
- customPresets.length > 0 && /* @__PURE__ */ jsxs58("div", { children: [
16255
- /* @__PURE__ */ jsx80(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block", children: t("themeProvider.designer.myThemes") }),
16256
- /* @__PURE__ */ jsx80("div", { className: "flex flex-col gap-1.5", children: customPresets.map((preset) => /* @__PURE__ */ jsx80(PresetCard, { preset, isCustom: true }, preset.name)) })
17277
+ customPresets.length > 0 && /* @__PURE__ */ jsxs59("div", { children: [
17278
+ /* @__PURE__ */ jsx81(ITText, { as: "span", className: "text-[11px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2.5 block", children: t("themeProvider.designer.myThemes") }),
17279
+ /* @__PURE__ */ jsx81("div", { className: "flex flex-col gap-1.5", children: customPresets.map((preset) => /* @__PURE__ */ jsx81(PresetCard, { preset, isCustom: true }, preset.name)) })
16257
17280
  ] }),
16258
- isSavingPreset && /* @__PURE__ */ jsxs58("div", { className: "flex flex-col gap-2 p-3 rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900/50", children: [
16259
- /* @__PURE__ */ jsx80(
17281
+ isSavingPreset && /* @__PURE__ */ jsxs59("div", { className: "flex flex-col gap-2 p-3 rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900/50", children: [
17282
+ /* @__PURE__ */ jsx81(
16260
17283
  ITInput,
16261
17284
  {
16262
17285
  name: "presetName",
@@ -16274,8 +17297,8 @@ function ITThemeProvider({
16274
17297
  }
16275
17298
  }
16276
17299
  ),
16277
- /* @__PURE__ */ jsxs58("div", { className: "flex gap-2", children: [
16278
- /* @__PURE__ */ jsx80(
17300
+ /* @__PURE__ */ jsxs59("div", { className: "flex gap-2", children: [
17301
+ /* @__PURE__ */ jsx81(
16279
17302
  ITButton,
16280
17303
  {
16281
17304
  label: t("themeProvider.designer.save"),
@@ -16286,7 +17309,7 @@ function ITThemeProvider({
16286
17309
  className: "flex-1"
16287
17310
  }
16288
17311
  ),
16289
- /* @__PURE__ */ jsx80(
17312
+ /* @__PURE__ */ jsx81(
16290
17313
  ITButton,
16291
17314
  {
16292
17315
  label: t("themeProvider.designer.cancelSave"),
@@ -16300,31 +17323,31 @@ function ITThemeProvider({
16300
17323
  )
16301
17324
  ] })
16302
17325
  ] }),
16303
- !isSavingPreset && /* @__PURE__ */ jsx80(
17326
+ !isSavingPreset && /* @__PURE__ */ jsx81(
16304
17327
  ITButton,
16305
17328
  {
16306
17329
  variant: "outlined",
16307
- icon: /* @__PURE__ */ jsx80(MdPalette, { size: 14 }),
17330
+ icon: /* @__PURE__ */ jsx81(MdPalette, { size: 14 }),
16308
17331
  label: t("themeProvider.designer.saveCurrent"),
16309
17332
  onClick: () => setIsSavingPreset(true),
16310
17333
  size: "sm"
16311
17334
  }
16312
17335
  ),
16313
- /* @__PURE__ */ jsx80(
17336
+ /* @__PURE__ */ jsx81(
16314
17337
  ITButton,
16315
17338
  {
16316
17339
  variant: "outlined",
16317
17340
  color: "danger",
16318
- icon: /* @__PURE__ */ jsx80(MdRefresh, { size: 14 }),
17341
+ icon: /* @__PURE__ */ jsx81(MdRefresh, { size: 14 }),
16319
17342
  label: t("themeProvider.designer.reset"),
16320
17343
  onClick: resetTheme,
16321
17344
  size: "sm"
16322
17345
  }
16323
17346
  )
16324
17347
  ] }),
16325
- /* @__PURE__ */ jsx80(ITDivider, { orientation: "vertical" }),
16326
- /* @__PURE__ */ jsxs58("div", { className: "flex-1 flex flex-col min-w-0", children: [
16327
- /* @__PURE__ */ jsx80(
17348
+ /* @__PURE__ */ jsx81(ITDivider, { orientation: "vertical" }),
17349
+ /* @__PURE__ */ jsxs59("div", { className: "flex-1 flex flex-col min-w-0", children: [
17350
+ /* @__PURE__ */ jsx81(
16328
17351
  tabs_default,
16329
17352
  {
16330
17353
  variant: "pill",
@@ -16332,7 +17355,7 @@ function ITThemeProvider({
16332
17355
  {
16333
17356
  id: "brand",
16334
17357
  label: t("themeProvider.tabs.brand"),
16335
- content: /* @__PURE__ */ jsx80("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
17358
+ content: /* @__PURE__ */ jsx81("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
16336
17359
  "primary",
16337
17360
  "secondary",
16338
17361
  "ternary",
@@ -16341,35 +17364,35 @@ function ITThemeProvider({
16341
17364
  "info",
16342
17365
  "alert",
16343
17366
  "warning"
16344
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17367
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16345
17368
  },
16346
17369
  {
16347
17370
  id: "layout",
16348
17371
  label: t("themeProvider.tabs.layout"),
16349
- content: /* @__PURE__ */ jsx80("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
17372
+ content: /* @__PURE__ */ jsx81("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
16350
17373
  "layout.sidebarBg",
16351
17374
  "layout.sidebarText",
16352
17375
  "layout.navbarBg",
16353
17376
  "layout.navbarText"
16354
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17377
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16355
17378
  },
16356
17379
  {
16357
17380
  id: "tables",
16358
17381
  label: t("themeProvider.tabs.tables"),
16359
- content: /* @__PURE__ */ jsx80("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
17382
+ content: /* @__PURE__ */ jsx81("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 max-h-[480px] overflow-y-auto pr-2 mt-3", children: [
16360
17383
  "table.headerBg",
16361
17384
  "table.headerText",
16362
17385
  "table.rowBg",
16363
17386
  "table.rowText",
16364
17387
  "table.rowHover"
16365
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17388
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16366
17389
  }
16367
17390
  ]
16368
17391
  }
16369
17392
  ),
16370
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center justify-end gap-3 mt-auto pt-4 border-t border-slate-100 dark:border-slate-800", children: [
16371
- /* @__PURE__ */ jsx80(ITText, { as: "p", className: "text-[11px] text-slate-400 mr-auto", children: t("themeProvider.designer.autosave") }),
16372
- /* @__PURE__ */ jsx80(
17393
+ /* @__PURE__ */ jsxs59("div", { className: "flex items-center justify-end gap-3 mt-auto pt-4 border-t border-slate-100 dark:border-slate-800", children: [
17394
+ /* @__PURE__ */ jsx81(ITText, { as: "p", className: "text-[11px] text-slate-400 mr-auto", children: t("themeProvider.designer.autosave") }),
17395
+ /* @__PURE__ */ jsx81(
16373
17396
  ITButton,
16374
17397
  {
16375
17398
  label: t("themeProvider.designer.close"),
@@ -16427,7 +17450,7 @@ export {
16427
17450
  dropfile_default as ITDropfile,
16428
17451
  ITEmptyState,
16429
17452
  ITField,
16430
- ITFlex,
17453
+ flex_default as ITFlex,
16431
17454
  ITFormBuilder,
16432
17455
  ITFormHeader,
16433
17456
  ITGrid,
@@ -16464,7 +17487,7 @@ export {
16464
17487
  ITTable,
16465
17488
  tabs_default as ITTabs,
16466
17489
  ITText,
16467
- ITTextarea,
17490
+ textarea_default as ITTextarea,
16468
17491
  ITThemeProvider,
16469
17492
  ITTimePicker,
16470
17493
  ITToast,
@@ -16476,13 +17499,16 @@ export {
16476
17499
  auditTree,
16477
17500
  axzyCatalog,
16478
17501
  axzyCatalogTypes,
17502
+ buildNavigationTree,
16479
17503
  buildVocabularyContract,
16480
17504
  countPendingNodes,
17505
+ createBindingResolver,
16481
17506
  createCatalog,
16482
17507
  createLimitTracker,
16483
17508
  createValidationSchema,
16484
17509
  en_default as enMessages,
16485
17510
  es_default as esMessages,
17511
+ flattenRoutes,
16486
17512
  formatPath,
16487
17513
  formatVocabularyForPrompt,
16488
17514
  getCatalogEntry,
@@ -16493,7 +17519,10 @@ export {
16493
17519
  isLightColor,
16494
17520
  isNodePending,
16495
17521
  issue,
17522
+ joinRoutePath,
17523
+ matchRoute,
16496
17524
  migrateSchema,
17525
+ navContainsRoute,
16497
17526
  parsePartialSchema,
16498
17527
  parsePath,
16499
17528
  propPath,
@@ -16503,6 +17532,7 @@ export {
16503
17532
  resolveCssColor,
16504
17533
  resolveLimits,
16505
17534
  resolveNode,
17535
+ routeHref,
16506
17536
  useClickOutside_default as useClickOutside,
16507
17537
  useDebouncedSearch,
16508
17538
  useEditableRow,
@@ -16512,7 +17542,9 @@ export {
16512
17542
  useITThemeSafe,
16513
17543
  useITTranslation,
16514
17544
  useJsonRender_default as useJsonRender,
17545
+ useSchemaStream,
16515
17546
  useTableState,
17547
+ validateRoutes,
16516
17548
  validateSchema
16517
17549
  };
16518
17550
  //# sourceMappingURL=index.js.map