@axzydev/axzy_ui_system 1.7.3 → 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 (61) hide show
  1. package/dist/index.cjs +1621 -594
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.cts +366 -12
  5. package/dist/index.d.ts +366 -12
  6. package/dist/index.js +1331 -313
  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/organisms/dropfile/dropfile.props.ts +8 -2
  20. package/src/components/organisms/dropfile/dropfile.tsx +17 -0
  21. package/src/i18n/locales/en.ts +7 -0
  22. package/src/i18n/locales/es.ts +7 -0
  23. package/src/index.ts +31 -3
  24. package/src/json-renderer/actions/effects.test.tsx +115 -0
  25. package/src/json-renderer/actions/effects.ts +291 -0
  26. package/src/json-renderer/actions/effectsChain.test.ts +117 -0
  27. package/src/json-renderer/binding/binding.test.tsx +168 -0
  28. package/src/json-renderer/binding/resolveValue.ts +193 -0
  29. package/src/json-renderer/estado-acciones.test.tsx +166 -0
  30. package/src/json-renderer/form/FormNode.tsx +92 -0
  31. package/src/json-renderer/form/form.test.tsx +148 -0
  32. package/src/json-renderer/form/formLength.test.tsx +99 -0
  33. package/src/json-renderer/form/rules.ts +162 -0
  34. package/src/json-renderer/index.ts +21 -0
  35. package/src/json-renderer/kernel/SchemaRenderer.tsx +83 -7
  36. package/src/json-renderer/kernel/capabilities.ts +30 -0
  37. package/src/json-renderer/kernel/renderNode.tsx +256 -3
  38. package/src/json-renderer/kernel/schemaRenderer.props.ts +29 -3
  39. package/src/json-renderer/kernel/slots.test.tsx +104 -0
  40. package/src/json-renderer/kernel/slots.ts +34 -0
  41. package/src/json-renderer/kernel/types.ts +4 -0
  42. package/src/json-renderer/routing/match.ts +82 -0
  43. package/src/json-renderer/routing/navigation.ts +71 -0
  44. package/src/json-renderer/routing/routes.ts +179 -0
  45. package/src/json-renderer/routing/routing.test.ts +147 -0
  46. package/src/json-renderer/seguridad.test.tsx +299 -0
  47. package/src/json-renderer/shared/errors.ts +1 -0
  48. package/src/json-renderer/stream/tolerantParse.ts +5 -0
  49. package/src/json-renderer/stream/useSchemaStream.test.tsx +143 -0
  50. package/src/json-renderer/stream/useSchemaStream.ts +227 -0
  51. package/src/json-renderer/validation/jsonSchema.test.ts +105 -0
  52. package/src/json-renderer/validation/jsonSchema.ts +317 -0
  53. package/src/json-renderer/validation/validate.ts +17 -0
  54. package/src/sandbox/i18n.ts +38 -0
  55. package/src/sandbox/useHashRoute.ts +2 -1
  56. package/src/showcases/DemoJsonDashboard.tsx +218 -103
  57. package/src/showcases/DemoJsonDocs.tsx +11 -11
  58. package/src/showcases/JsonScreenShowcase.tsx +43 -53
  59. package/src/showcases/demoApp/demoJson.test.tsx +241 -0
  60. package/src/showcases/demoApp/routes.test.ts +63 -0
  61. 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":
@@ -8993,6 +9022,8 @@ function ITLineBarChart({
8993
9022
  barLabel,
8994
9023
  lineColor = "#10b981",
8995
9024
  barColor = "#3b82f6",
9025
+ showLine = true,
9026
+ showBars = true,
8996
9027
  height = 240,
8997
9028
  formatValue,
8998
9029
  formatAxis,
@@ -9010,8 +9041,11 @@ function ITLineBarChart({
9010
9041
  const plotWidth = width - padding.left - padding.right;
9011
9042
  const plotHeight = height - padding.top - padding.bottom;
9012
9043
  const max = useMemo13(
9013
- () => Math.max(...data.flatMap((d) => [d.line, d.bar]), 1),
9014
- [data]
9044
+ () => Math.max(
9045
+ ...data.flatMap((d) => [showLine ? d.line : 0, showBars ? d.bar : 0]),
9046
+ 1
9047
+ ),
9048
+ [data, showLine, showBars]
9015
9049
  );
9016
9050
  const gridValues = [0, 0.25, 0.5, 0.75, 1].map((f) => max * f);
9017
9051
  const step = data.length > 0 ? plotWidth / data.length : plotWidth;
@@ -9055,7 +9089,7 @@ function ITLineBarChart({
9055
9089
  ),
9056
9090
  /* @__PURE__ */ jsx64("text", { x: padding.left - 8, y: y(value) + 3, textAnchor: "end", fontSize: 10, fill: "#94a3b8", children: resolvedFormatAxis(Math.round(value)) })
9057
9091
  ] }, i)),
9058
- data.map((d, i) => /* @__PURE__ */ jsx64(
9092
+ showBars && data.map((d, i) => /* @__PURE__ */ jsx64(
9059
9093
  "rect",
9060
9094
  {
9061
9095
  x: x(i) - barWidth / 2,
@@ -9068,8 +9102,8 @@ function ITLineBarChart({
9068
9102
  },
9069
9103
  `bar-${d.label}`
9070
9104
  )),
9071
- areaPath && /* @__PURE__ */ jsx64("path", { d: areaPath, fill: `url(#area-${gradientId})` }),
9072
- data.length > 0 && /* @__PURE__ */ jsx64(
9105
+ showLine && areaPath && /* @__PURE__ */ jsx64("path", { d: areaPath, fill: `url(#area-${gradientId})` }),
9106
+ showLine && data.length > 0 && /* @__PURE__ */ jsx64(
9073
9107
  "polyline",
9074
9108
  {
9075
9109
  points: linePoints,
@@ -9080,7 +9114,7 @@ function ITLineBarChart({
9080
9114
  strokeLinejoin: "round"
9081
9115
  }
9082
9116
  ),
9083
- data.map((d, i) => /* @__PURE__ */ jsx64(
9117
+ showLine && data.map((d, i) => /* @__PURE__ */ jsx64(
9084
9118
  "circle",
9085
9119
  {
9086
9120
  cx: x(i),
@@ -9107,12 +9141,12 @@ function ITLineBarChart({
9107
9141
  role: "status",
9108
9142
  children: [
9109
9143
  /* @__PURE__ */ jsx64("p", { className: "text-[10px] font-semibold", style: { color: "#e2e8f0" }, children: active.label }),
9110
- /* @__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: [
9111
9145
  resolvedLineLabel,
9112
9146
  ": ",
9113
9147
  resolvedFormatValue(active.line)
9114
9148
  ] }),
9115
- /* @__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: [
9116
9150
  resolvedBarLabel,
9117
9151
  ": ",
9118
9152
  resolvedFormatValue(active.bar)
@@ -9121,11 +9155,11 @@ function ITLineBarChart({
9121
9155
  }
9122
9156
  ),
9123
9157
  /* @__PURE__ */ jsxs45("ul", { className: "flex flex-wrap items-center gap-4 text-[11px]", style: { color: "#475569" }, children: [
9124
- /* @__PURE__ */ jsxs45("li", { children: [
9158
+ showLine && /* @__PURE__ */ jsxs45("li", { children: [
9125
9159
  /* @__PURE__ */ jsx64("span", { className: "h-2.5 w-2.5 rounded-sm", style: { background: lineColor }, "aria-hidden": true }),
9126
9160
  resolvedLineLabel
9127
9161
  ] }),
9128
- /* @__PURE__ */ jsxs45("li", { children: [
9162
+ showBars && /* @__PURE__ */ jsxs45("li", { children: [
9129
9163
  /* @__PURE__ */ jsx64("span", { className: "h-2.5 w-2.5 rounded-sm", style: { background: barColor }, "aria-hidden": true }),
9130
9164
  resolvedBarLabel
9131
9165
  ] })
@@ -9774,6 +9808,7 @@ function ITTable({
9774
9808
 
9775
9809
  // src/components/atoms/textarea/textarea.tsx
9776
9810
  import clsx46 from "clsx";
9811
+ import { forwardRef as forwardRef2 } from "react";
9777
9812
  import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
9778
9813
  var resizeMap = {
9779
9814
  none: "resize-none",
@@ -9781,7 +9816,7 @@ var resizeMap = {
9781
9816
  horizontal: "resize-x",
9782
9817
  both: "resize"
9783
9818
  };
9784
- function ITTextarea({
9819
+ var ITTextarea = forwardRef2(function ITTextarea2({
9785
9820
  value,
9786
9821
  onChange,
9787
9822
  label,
@@ -9792,13 +9827,16 @@ function ITTextarea({
9792
9827
  className,
9793
9828
  name,
9794
9829
  maxLength,
9795
- resize = "vertical"
9796
- }) {
9830
+ resize = "vertical",
9831
+ onKeyDown,
9832
+ autoFocus = false
9833
+ }, ref) {
9797
9834
  return /* @__PURE__ */ jsxs47("div", { className: clsx46("flex flex-col gap-1.5", className), children: [
9798
9835
  label && /* @__PURE__ */ jsx66(ITText, { as: "label", className: inputLabel(!!error), htmlFor: name, children: label }),
9799
9836
  /* @__PURE__ */ jsx66(
9800
9837
  "textarea",
9801
9838
  {
9839
+ ref,
9802
9840
  id: name,
9803
9841
  name,
9804
9842
  value,
@@ -9807,6 +9845,8 @@ function ITTextarea({
9807
9845
  rows,
9808
9846
  disabled,
9809
9847
  maxLength,
9848
+ onKeyDown,
9849
+ autoFocus,
9810
9850
  className: clsx46(
9811
9851
  "w-full border border-solid transition-all duration-200 rounded-lg px-3 py-2 text-sm outline-none",
9812
9852
  "focus:ring-2",
@@ -9818,7 +9858,9 @@ function ITTextarea({
9818
9858
  ),
9819
9859
  error && /* @__PURE__ */ jsx66(ITText, { as: "span", className: inputError, children: error })
9820
9860
  ] });
9821
- }
9861
+ });
9862
+ ITTextarea.displayName = "ITTextarea";
9863
+ var textarea_default = ITTextarea;
9822
9864
 
9823
9865
  // src/components/molecules/tabs/tabs.tsx
9824
9866
  import { useState as useState31 } from "react";
@@ -12185,7 +12227,7 @@ function EditorToggle({
12185
12227
  }
12186
12228
 
12187
12229
  // src/json-renderer/kernel/SchemaRenderer.tsx
12188
- 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";
12189
12231
 
12190
12232
  // src/types/loader.types.ts
12191
12233
  var sizeClasses = {
@@ -12496,7 +12538,7 @@ var AXZY_CATALOG_ENTRIES = [
12496
12538
  },
12497
12539
  {
12498
12540
  type: "ITFlex",
12499
- component: ITFlex,
12541
+ component: flex_default,
12500
12542
  children: true,
12501
12543
  summary: "Contenedor flex completo.",
12502
12544
  props: {
@@ -12629,6 +12671,192 @@ var AXZY_EXCLUDED_TYPES = {
12629
12671
  var axzyCatalog = createCatalog(AXZY_CATALOG_ENTRIES, AXZY_EXCLUDED_TYPES);
12630
12672
  var axzyCatalogTypes = Object.keys(axzyCatalog.entries);
12631
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
+
12632
12860
  // src/json-renderer/shared/limits.ts
12633
12861
  var DEFAULT_LIMITS = {
12634
12862
  maxNodes: 5e3,
@@ -12672,46 +12900,25 @@ function createLimitTracker(limits = DEFAULT_LIMITS) {
12672
12900
  };
12673
12901
  }
12674
12902
 
12675
- // src/json-renderer/kernel/NodeBoundary.tsx
12676
- import React16 from "react";
12677
-
12678
- // src/json-renderer/shared/errors.ts
12679
- var JsonEngineError = class extends Error {
12680
- constructor(code, message, path, hint) {
12681
- super(`${code} ${path ? `en ${path}: ` : ""}${message}`);
12682
- /** Código estable del catálogo de avisos. */
12683
- __publicField(this, "code");
12684
- /** Ruta del esquema donde se produjo. */
12685
- __publicField(this, "path");
12686
- /** Sugerencia accionable. */
12687
- __publicField(this, "hint");
12688
- this.name = "JsonEngineError";
12689
- this.code = code;
12690
- this.path = path;
12691
- 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;
12692
12909
  }
12693
- /** Convierte el error en el aviso que consume la interfaz y el informe. */
12694
- toIssue(severity = "error") {
12695
- return {
12696
- code: this.code,
12697
- severity,
12698
- message: this.message.replace(/^JR\d{3}\s?(en .*?: )?/, ""),
12699
- path: this.path,
12700
- hint: this.hint
12701
- };
12702
- }
12703
- };
12704
- function issue(code, message, path = "", options = {}) {
12705
- return {
12706
- code,
12707
- severity: options.severity ?? "error",
12708
- message,
12709
- path,
12710
- hint: options.hint
12711
- };
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));
12712
12918
  }
12713
12919
 
12714
12920
  // src/json-renderer/kernel/NodeBoundary.tsx
12921
+ import React16 from "react";
12715
12922
  var NodeBoundary = class extends React16.Component {
12716
12923
  constructor() {
12717
12924
  super(...arguments);
@@ -13059,48 +13266,7 @@ function isNodePending(node) {
13059
13266
  }
13060
13267
 
13061
13268
  // src/json-renderer/kernel/renderNode.tsx
13062
- import React17 from "react";
13063
-
13064
- // src/json-renderer/shared/paths.ts
13065
- function pushPath(path, segment) {
13066
- return [...path, segment];
13067
- }
13068
- function formatPath(path) {
13069
- let out = "";
13070
- for (const segment of path) {
13071
- if (typeof segment === "number") out += `[${segment}]`;
13072
- else out += out ? `.${segment}` : segment;
13073
- }
13074
- return out;
13075
- }
13076
- function parsePath(rendered) {
13077
- if (!rendered) return [];
13078
- return rendered.split(/\.(?![^[]*])/).flatMap((part) => {
13079
- const match = part.match(/^([^[\]]*)((?:\[\d+\])*)$/);
13080
- if (!match) return [part];
13081
- const [, key, indexes] = match;
13082
- const segments = key ? [key] : [];
13083
- for (const index of indexes.match(/\d+/g) ?? []) segments.push(Number(index));
13084
- return segments;
13085
- });
13086
- }
13087
- function readPath(source, path) {
13088
- let cursor = source;
13089
- for (const segment of path) {
13090
- if (cursor === null || typeof cursor !== "object") return void 0;
13091
- cursor = cursor[segment];
13092
- }
13093
- return cursor;
13094
- }
13095
- function hasPath(source, path) {
13096
- if (path.length === 0) return true;
13097
- const parent = readPath(source, path.slice(0, -1));
13098
- if (parent === null || typeof parent !== "object") return false;
13099
- return Object.prototype.hasOwnProperty.call(parent, path[path.length - 1]);
13100
- }
13101
- function propPath(nodePath, prop) {
13102
- return pushPath(pushPath(nodePath, "props"), prop);
13103
- }
13269
+ import React18 from "react";
13104
13270
 
13105
13271
  // src/json-renderer/catalog/resolve.ts
13106
13272
  function isSchemaReference(value) {
@@ -13241,11 +13407,457 @@ function resolveNode(node, catalog, path) {
13241
13407
  return { ok: true, entry, props, actions, issues };
13242
13408
  }
13243
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
+
13244
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
+ }
13245
13724
  function childList(node) {
13246
13725
  if (!node || node.children === void 0 || node.children === null) return [];
13247
13726
  return Array.isArray(node.children) ? node.children : [node.children];
13248
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
+ }
13249
13861
  function renderNode(node, options) {
13250
13862
  const { catalog, path, issues, renderChildren } = options;
13251
13863
  if (!node || typeof node !== "object") {
@@ -13254,6 +13866,12 @@ function renderNode(node, options) {
13254
13866
  if (isNodePending(node)) {
13255
13867
  return options.pendingFallback ?? null;
13256
13868
  }
13869
+ if (isSlotNode(node)) {
13870
+ return renderSlot(node, options);
13871
+ }
13872
+ if (isFormNode(node)) {
13873
+ return renderForm(node, options);
13874
+ }
13257
13875
  const resolved = resolveNode(node, catalog, path);
13258
13876
  issues.push(...resolved.issues);
13259
13877
  if (!resolved.ok) {
@@ -13264,15 +13882,37 @@ function renderNode(node, options) {
13264
13882
  for (const [name, value] of Object.entries(props)) {
13265
13883
  finalProps[name] = options.resolveValue ? options.resolveValue(value, path) : value;
13266
13884
  }
13885
+ if (node.type === "ITDataTable" && finalProps.columns !== void 0) {
13886
+ finalProps.columns = prepararColumnas(finalProps.columns, node, options, path);
13887
+ }
13267
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
+ }
13268
13899
  const handler = options.resolveAction?.(node, name, action, path);
13269
- 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
+ }
13270
13910
  }
13271
13911
  const content = renderChildren ? renderChildren(node, path) : null;
13272
13912
  const rawText = entry.text && node.text !== void 0 ? node.text : void 0;
13273
13913
  const text = rawText === void 0 ? void 0 : options.resolveValue ? options.resolveValue(rawText, path) : rawText;
13274
13914
  const children = content ?? text;
13275
- const element = React17.createElement(
13915
+ const element = React18.createElement(
13276
13916
  entry.component,
13277
13917
  { ...finalProps, key: node.id ?? path.join("-"), id: node.id },
13278
13918
  children
@@ -13328,7 +13968,7 @@ function countPendingNodes(schema) {
13328
13968
  }
13329
13969
 
13330
13970
  // src/json-renderer/kernel/SchemaRenderer.tsx
13331
- import { Fragment as Fragment13, jsx as jsx75 } from "react/jsx-runtime";
13971
+ import { Fragment as Fragment13, jsx as jsx76 } from "react/jsx-runtime";
13332
13972
  function renderTree(node, path, context, level) {
13333
13973
  if (!node || typeof node !== "object") return null;
13334
13974
  if (level > context.limits.maxDepth) return null;
@@ -13338,6 +13978,16 @@ function renderTree(node, path, context, level) {
13338
13978
  issues.push(issue2);
13339
13979
  context.onIssue?.(issue2);
13340
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
+ }
13341
13991
  const issuesBefore = issues.length;
13342
13992
  const element = renderNode(node, {
13343
13993
  catalog: context.catalog,
@@ -13346,6 +13996,12 @@ function renderTree(node, path, context, level) {
13346
13996
  resolveValue: context.resolveValue,
13347
13997
  resolveAction: context.resolveAction,
13348
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,
13349
14005
  renderChildren: (current, currentPath) => {
13350
14006
  const children = childList(current);
13351
14007
  if (children.length === 0) return void 0;
@@ -13358,7 +14014,7 @@ function renderTree(node, path, context, level) {
13358
14014
  context.onIssue?.(issues[index]);
13359
14015
  }
13360
14016
  const fallback = node.fallback ? renderTree(node.fallback, [...path, "fallback"], context, level + 1) : context.pendingFallback ?? null;
13361
- const wrapped = /* @__PURE__ */ jsx75(
14017
+ const wrapped = /* @__PURE__ */ jsx76(
13362
14018
  NodeBoundary,
13363
14019
  {
13364
14020
  path: path.join("."),
@@ -13380,6 +14036,11 @@ function ITSchemaRenderer({
13380
14036
  schema,
13381
14037
  catalog = axzyCatalog,
13382
14038
  limits,
14039
+ params,
14040
+ dataHandlers,
14041
+ slots,
14042
+ effects,
14043
+ capabilities,
13383
14044
  resolveValue,
13384
14045
  resolveAction,
13385
14046
  pendingFallback,
@@ -13387,6 +14048,21 @@ function ITSchemaRenderer({
13387
14048
  className
13388
14049
  }) {
13389
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
+ );
13390
14066
  const issues = [];
13391
14067
  const nodeIds = /* @__PURE__ */ new Set();
13392
14068
  const audit = useMemo16(
@@ -13400,16 +14076,37 @@ function ITSchemaRenderer({
13400
14076
  limits: resolvedLimits,
13401
14077
  issues,
13402
14078
  onIssue,
13403
- 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
+ }),
13404
14088
  resolveAction,
13405
- pendingFallback
14089
+ pendingFallback,
14090
+ slots,
14091
+ effects,
14092
+ capabilities,
14093
+ setState: escribirEstado
13406
14094
  }),
13407
14095
  // `issues` es un array nuevo en cada render a propósito: acumular avisos
13408
14096
  // entre renders duplicaría los avisos de esquemas que no han cambiado.
13409
14097
  // eslint-disable-next-line react-hooks/exhaustive-deps
13410
- [catalog, resolvedLimits, onIssue, resolveValue, resolveAction, pendingFallback]
14098
+ [schema, params, valoresPantalla, escribirEstado, dataHandlers, slots, effects, capabilities, catalog, resolvedLimits, onIssue, resolveValue, resolveAction, pendingFallback]
13411
14099
  );
13412
- 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(
13413
14110
  (node) => Boolean(node) && typeof node === "object"
13414
14111
  ) : [];
13415
14112
  const children = content.slice(0, resolvedLimits.maxNodes).map((node, index) => renderTree(node, ["content", index], context, 0)).filter(Boolean);
@@ -13435,7 +14132,159 @@ function ITSchemaRenderer({
13435
14132
  for (const issue2 of all) onIssue(issue2);
13436
14133
  }, [signature, onIssue]);
13437
14134
  if (!schema || children.length === 0) return null;
13438
- 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);
13439
14288
  }
13440
14289
 
13441
14290
  // src/json-renderer/validation/validate.ts
@@ -13446,6 +14295,17 @@ function validateNodes(node, path, catalog, errors, warnings) {
13446
14295
  return 0;
13447
14296
  }
13448
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
+ }
13449
14309
  const resolved = resolveNode(node, catalog, path);
13450
14310
  for (const item of resolved.issues) {
13451
14311
  (item.severity === "error" ? errors : warnings).push(item);
@@ -13628,8 +14488,143 @@ function formatVocabularyForPrompt(contract) {
13628
14488
  return lines.join("\n");
13629
14489
  }
13630
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
+
13631
14626
  // src/components/organisms/dropfile/dropfile.tsx
13632
- import { useState as useState37, useEffect as useEffect19 } from "react";
14627
+ import { useState as useState40, useEffect as useEffect20 } from "react";
13633
14628
  import { useDropzone } from "react-dropzone";
13634
14629
  import clsx54 from "clsx";
13635
14630
 
@@ -13659,11 +14654,12 @@ var UploadStatus = /* @__PURE__ */ ((UploadStatus2) => {
13659
14654
  })(UploadStatus || {});
13660
14655
 
13661
14656
  // src/components/organisms/dropfile/dropfile.tsx
13662
- 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";
13663
14658
  var ITDropfile = ({
13664
14659
  onFileSelect,
13665
14660
  onCancel,
13666
14661
  onSubmit,
14662
+ autoUpload = false,
13667
14663
  contentClassName,
13668
14664
  containerClassName,
13669
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 */],
@@ -13676,15 +14672,15 @@ var ITDropfile = ({
13676
14672
  modalTitle
13677
14673
  }) => {
13678
14674
  const { t } = useITTranslation();
13679
- const [isModalOpen, setIsModalOpen] = useState37(false);
13680
- const [selectedFile, setSelectedFile] = useState37(null);
13681
- const [fileType, setFileType] = useState37(null);
13682
- const [imagePreview, setImagePreview] = useState37(initialPreviewUrl || null);
13683
- const [isConfirmed, setIsConfirmed] = useState37(false);
13684
- 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(
13685
14681
  initialPreviewUrl ? "subido" /* UPLOADED */ : "pendiente" /* PENDING */
13686
14682
  );
13687
- useEffect19(() => {
14683
+ useEffect20(() => {
13688
14684
  if (initialPreviewUrl && !selectedFile) {
13689
14685
  setImagePreview(initialPreviewUrl);
13690
14686
  if (externalStatus === void 0) setInternalUploadStatus("subido" /* UPLOADED */);
@@ -13799,11 +14795,23 @@ var ITDropfile = ({
13799
14795
  }
13800
14796
  };
13801
14797
  const { label, color, dotColor } = config2[status];
13802
- return /* @__PURE__ */ jsxs54("div", { className: `inline-flex items-center gap-2 px-2.5 py-1 rounded-full border ${color}`, children: [
13803
- /* @__PURE__ */ jsx76("div", { className: `w-2 h-2 rounded-full ${dotColor}` }),
13804
- /* @__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 })
13805
14801
  ] });
13806
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
+ };
13807
14815
  const onDrop = (acceptedFiles) => {
13808
14816
  const file = acceptedFiles[0];
13809
14817
  if (file) {
@@ -13819,6 +14827,7 @@ var ITDropfile = ({
13819
14827
  const previewUrl = URL.createObjectURL(file);
13820
14828
  setImagePreview(previewUrl);
13821
14829
  }
14830
+ if (autoUpload) void runAutoUpload(file);
13822
14831
  } else {
13823
14832
  alert(t("dropfile.fileTypeNotAllowed"));
13824
14833
  setSelectedFile(null);
@@ -13833,12 +14842,12 @@ var ITDropfile = ({
13833
14842
  accept: getAcceptedFileTypes(),
13834
14843
  maxFiles: 1
13835
14844
  });
13836
- useEffect19(() => {
14845
+ useEffect20(() => {
13837
14846
  const renderPDF = async () => {
13838
14847
  };
13839
14848
  renderPDF();
13840
14849
  }, [selectedFile, fileType]);
13841
- useEffect19(() => {
14850
+ useEffect20(() => {
13842
14851
  return () => {
13843
14852
  if (imagePreview) {
13844
14853
  URL.revokeObjectURL(imagePreview);
@@ -13875,7 +14884,7 @@ var ITDropfile = ({
13875
14884
  const handleDelete = () => {
13876
14885
  handleCancel();
13877
14886
  };
13878
- useEffect19(() => {
14887
+ useEffect20(() => {
13879
14888
  if (view === "button" && isConfirmed && uploadStatus === "subido" /* UPLOADED */) {
13880
14889
  const timeout = setTimeout(() => {
13881
14890
  setIsModalOpen(false);
@@ -13892,21 +14901,21 @@ var ITDropfile = ({
13892
14901
  return () => clearTimeout(timeout);
13893
14902
  }
13894
14903
  }, [view, isConfirmed, uploadStatus, externalStatus, onStatusChange]);
13895
- const headerRow = /* @__PURE__ */ jsxs54("div", { className: "flex items-center justify-between mb-2", children: [
13896
- /* @__PURE__ */ jsxs54("label", { className: "block text-sm font-semibold text-secondary-700", children: [
13897
- /* @__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: [
13898
14907
  t("dropfile.upload"),
13899
14908
  " "
13900
14909
  ] }),
13901
- /* @__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: [
13902
14911
  "(",
13903
14912
  getFileExtensions(),
13904
14913
  ")"
13905
14914
  ] })
13906
14915
  ] }),
13907
- showStatusBadge && selectedFile && /* @__PURE__ */ jsx76(StatusBadge, { status: uploadStatus })
14916
+ showStatusBadge && selectedFile && /* @__PURE__ */ jsx77(StatusBadge, { status: uploadStatus })
13908
14917
  ] });
13909
- const dropZoneOrPreview = /* @__PURE__ */ jsx76(Fragment14, { children: !selectedFile && !imagePreview ? /* @__PURE__ */ jsxs54(
14918
+ const dropZoneOrPreview = /* @__PURE__ */ jsx77(Fragment14, { children: !selectedFile && !imagePreview ? /* @__PURE__ */ jsxs55(
13910
14919
  "div",
13911
14920
  {
13912
14921
  ...getRootProps(),
@@ -13916,41 +14925,41 @@ var ITDropfile = ({
13916
14925
  ${isDragActive ? "border-primary-500 bg-primary-50 scale-[1.01]" : "border-secondary-300 bg-white hover:border-primary-400 hover:bg-secondary-50"}
13917
14926
  `,
13918
14927
  children: [
13919
- /* @__PURE__ */ jsx76("input", { ...getInputProps() }),
13920
- /* @__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(
13921
14930
  "svg",
13922
14931
  {
13923
14932
  className: `w-6 h-6 transition-colors duration-300 ${isDragActive ? "text-primary-600" : "text-secondary-400 group-hover:text-primary-500"}`,
13924
14933
  fill: "none",
13925
14934
  viewBox: "0 0 24 24",
13926
14935
  stroke: "currentColor",
13927
- 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" })
13928
14937
  }
13929
14938
  ) }),
13930
- /* @__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") }) })
13931
14940
  ]
13932
14941
  }
13933
- ) : /* @__PURE__ */ jsxs54("div", { className: "w-full bg-white border border-secondary-200 rounded-xl shadow-sm overflow-hidden animate-fade-in", children: [
13934
- /* @__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: [
13935
- /* @__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" }) }) }),
13936
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0", children: [
13937
- /* @__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") }),
13938
- /* @__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" : "" })
13939
14948
  ] })
13940
14949
  ] }) }),
13941
- /* @__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(
13942
14951
  "img",
13943
14952
  {
13944
14953
  src: imagePreview,
13945
14954
  alt: t("dropfile.previewAlt"),
13946
14955
  className: "w-full h-full object-contain max-h-[200px]"
13947
14956
  }
13948
- ) : /* @__PURE__ */ jsxs54("div", { className: "py-8 flex flex-col items-center text-secondary-400", children: [
13949
- /* @__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" }) }),
13950
- /* @__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") })
13951
14960
  ] }) }),
13952
- /* @__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: [
13953
- /* @__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(
13954
14963
  ITButton,
13955
14964
  {
13956
14965
  type: "button",
@@ -13958,10 +14967,10 @@ var ITDropfile = ({
13958
14967
  color: "secondary",
13959
14968
  size: "sm",
13960
14969
  onClick: handleCancel,
13961
- children: /* @__PURE__ */ jsx76(ITText, { children: t("common.cancel") })
14970
+ children: /* @__PURE__ */ jsx77(ITText, { children: t("common.cancel") })
13962
14971
  }
13963
14972
  ),
13964
- /* @__PURE__ */ jsx76(
14973
+ /* @__PURE__ */ jsx77(
13965
14974
  ITButton,
13966
14975
  {
13967
14976
  type: "button",
@@ -13969,13 +14978,13 @@ var ITDropfile = ({
13969
14978
  color: "primary",
13970
14979
  size: "sm",
13971
14980
  onClick: handleConfirm,
13972
- children: /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-2", children: [
13973
- /* @__PURE__ */ jsx76(ITText, { children: t("common.confirm") }),
13974
- /* @__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" }) })
13975
14984
  ] })
13976
14985
  }
13977
14986
  )
13978
- ] }) : /* @__PURE__ */ jsxs54(
14987
+ ] }) : /* @__PURE__ */ jsxs55(
13979
14988
  ITButton,
13980
14989
  {
13981
14990
  type: "button",
@@ -13984,12 +14993,12 @@ var ITDropfile = ({
13984
14993
  size: "sm",
13985
14994
  onClick: handleDelete,
13986
14995
  children: [
13987
- /* @__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" }) }),
13988
- /* @__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") })
13989
14998
  ]
13990
14999
  }
13991
15000
  ) }),
13992
- 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(
13993
15002
  "div",
13994
15003
  {
13995
15004
  className: "bg-primary-600 h-1.5 rounded-full transition-all duration-1000 ease-out",
@@ -14002,8 +15011,8 @@ var ITDropfile = ({
14002
15011
  ] }) });
14003
15012
  if (view === "button") {
14004
15013
  const hasFile = Boolean(selectedFile || imagePreview);
14005
- return /* @__PURE__ */ jsxs54("div", { className: clsx54("inline-block", containerClassName), children: [
14006
- /* @__PURE__ */ jsx76(
15014
+ return /* @__PURE__ */ jsxs55("div", { className: clsx54("inline-block", containerClassName), children: [
15015
+ /* @__PURE__ */ jsx77(
14007
15016
  ITButton,
14008
15017
  {
14009
15018
  type: "button",
@@ -14011,20 +15020,20 @@ var ITDropfile = ({
14011
15020
  color: hasFile ? "primary" : "secondary",
14012
15021
  size: "sm",
14013
15022
  onClick: () => setIsModalOpen(true),
14014
- children: /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-2 max-w-[220px]", children: [
14015
- /* @__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" }) }),
14016
- /* @__PURE__ */ jsx76(ITText, { className: "truncate", children: selectedFile?.name || (hasFile ? t("dropfile.fileLoaded") : buttonLabel ?? t("dropfile.upload")) }),
14017
- 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 })
14018
15027
  ] })
14019
15028
  }
14020
15029
  ),
14021
- /* @__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: [
14022
15031
  headerRow,
14023
15032
  dropZoneOrPreview
14024
15033
  ] }) })
14025
15034
  ] });
14026
15035
  }
14027
- 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: [
14028
15037
  headerRow,
14029
15038
  dropZoneOrPreview
14030
15039
  ] });
@@ -14032,13 +15041,13 @@ var ITDropfile = ({
14032
15041
  var dropfile_default = ITDropfile;
14033
15042
 
14034
15043
  // src/components/templates/layout/layout.tsx
14035
- import { useState as useState39 } from "react";
15044
+ import { useState as useState42 } from "react";
14036
15045
  import clsx55 from "clsx";
14037
15046
 
14038
15047
  // src/components/organisms/topbar/topbar.tsx
14039
15048
  import { FaUserCircle as FaUserCircle2, FaBars } from "react-icons/fa";
14040
- import { useRef as useRef24, useState as useState38 } from "react";
14041
- 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";
14042
15051
  function ITTopBar({
14043
15052
  logo,
14044
15053
  logoText,
@@ -14055,10 +15064,10 @@ function ITTopBar({
14055
15064
  const flat = useITFlatAppearance();
14056
15065
  const { t } = useITTranslation();
14057
15066
  const initials = (userMenu?.userName ?? "").trim().split(/\s+/).slice(0, 2).map((word) => word.charAt(0).toUpperCase()).join("");
14058
- const [isUserMenuOpen, setIsUserMenuOpen] = useState38(false);
15067
+ const [isUserMenuOpen, setIsUserMenuOpen] = useState41(false);
14059
15068
  const userMenuRef = useRef24(null);
14060
15069
  useClickOutside_default(userMenuRef, () => setIsUserMenuOpen(false));
14061
- return /* @__PURE__ */ jsx77(
15070
+ return /* @__PURE__ */ jsx78(
14062
15071
  "header",
14063
15072
  {
14064
15073
  className: `sticky top-0 z-40 transition-all duration-300 ${flat ? "" : "backdrop-blur-md"}`,
@@ -14067,9 +15076,9 @@ function ITTopBar({
14067
15076
  borderBottom: "1px solid var(--it-topbar-border, rgba(15, 23, 42, 0.06))",
14068
15077
  boxShadow: flat ? "none" : "var(--shadow-xs)"
14069
15078
  },
14070
- children: /* @__PURE__ */ jsxs55("div", { className: `flex items-center justify-between px-6 lg:px-8 ${flat ? "h-[64px]" : "h-[72px]"}`, children: [
14071
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-5", children: [
14072
- 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(
14073
15082
  "button",
14074
15083
  {
14075
15084
  type: "button",
@@ -14081,12 +15090,12 @@ function ITTopBar({
14081
15090
  onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--it-topbar-user-hover, #f1f5f9)",
14082
15091
  onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
14083
15092
  onClick: onToggleMobileMenu,
14084
- children: /* @__PURE__ */ jsx77(FaBars, { className: "w-[1.125rem] h-[1.125rem]" })
15093
+ children: /* @__PURE__ */ jsx78(FaBars, { className: "w-[1.125rem] h-[1.125rem]" })
14085
15094
  }
14086
15095
  ),
14087
- /* @__PURE__ */ jsxs55("div", { className: `items-center gap-3 ${hideBrandOnDesktop ? "flex lg:hidden" : "flex"}`, children: [
14088
- logo && /* @__PURE__ */ jsx77("div", { className: "flex-shrink-0 drop-shadow-sm", children: logo }),
14089
- 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(
14090
15099
  ITText,
14091
15100
  {
14092
15101
  as: "span",
@@ -14096,7 +15105,7 @@ function ITTopBar({
14096
15105
  }
14097
15106
  )
14098
15107
  ] }),
14099
- 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(
14100
15109
  "button",
14101
15110
  {
14102
15111
  onClick: () => onNavItemClick?.(item.id),
@@ -14110,19 +15119,19 @@ function ITTopBar({
14110
15119
  e.currentTarget.style.color = "var(--it-topbar-text, #475569)";
14111
15120
  e.currentTarget.style.backgroundColor = "transparent";
14112
15121
  },
14113
- children: /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
14114
- item.icon && /* @__PURE__ */ jsx77("span", { className: "opacity-70", children: item.icon }),
14115
- /* @__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 })
14116
15125
  ] })
14117
15126
  },
14118
15127
  item.id
14119
15128
  )) })
14120
15129
  ] }),
14121
- 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 }) }),
14122
- (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: [
14123
15132
  children,
14124
- userMenu && /* @__PURE__ */ jsxs55("div", { className: "relative", children: [
14125
- /* @__PURE__ */ jsxs55(
15133
+ userMenu && /* @__PURE__ */ jsxs56("div", { className: "relative", children: [
15134
+ /* @__PURE__ */ jsxs56(
14126
15135
  "button",
14127
15136
  {
14128
15137
  type: "button",
@@ -14138,15 +15147,15 @@ function ITTopBar({
14138
15147
  },
14139
15148
  onClick: () => setIsUserMenuOpen(!isUserMenuOpen),
14140
15149
  children: [
14141
- /* @__PURE__ */ jsxs55("div", { className: "relative", children: [
14142
- userMenu.userImage ? /* @__PURE__ */ jsx77(
15150
+ /* @__PURE__ */ jsxs56("div", { className: "relative", children: [
15151
+ userMenu.userImage ? /* @__PURE__ */ jsx78(
14143
15152
  "img",
14144
15153
  {
14145
15154
  className: "w-9 h-9 rounded-full object-cover ring-2 ring-white shadow-sm",
14146
15155
  src: userMenu.userImage,
14147
15156
  alt: t("common.userAvatar")
14148
15157
  }
14149
- ) : flat && initials ? /* @__PURE__ */ jsx77(
15158
+ ) : flat && initials ? /* @__PURE__ */ jsx78(
14150
15159
  "div",
14151
15160
  {
14152
15161
  "aria-hidden": "true",
@@ -14157,11 +15166,11 @@ function ITTopBar({
14157
15166
  },
14158
15167
  children: initials
14159
15168
  }
14160
- ) : /* @__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)" } }) }),
14161
- !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" })
14162
15171
  ] }),
14163
- /* @__PURE__ */ jsxs55("div", { className: `hidden sm:flex flex-col py-0.5 ${flat ? "text-right" : "text-left"}`, children: [
14164
- /* @__PURE__ */ jsx77(
15172
+ /* @__PURE__ */ jsxs56("div", { className: `hidden sm:flex flex-col py-0.5 ${flat ? "text-right" : "text-left"}`, children: [
15173
+ /* @__PURE__ */ jsx78(
14165
15174
  ITText,
14166
15175
  {
14167
15176
  as: "span",
@@ -14170,7 +15179,7 @@ function ITTopBar({
14170
15179
  children: userMenu.userName
14171
15180
  }
14172
15181
  ),
14173
- /* @__PURE__ */ jsx77(
15182
+ /* @__PURE__ */ jsx78(
14174
15183
  ITText,
14175
15184
  {
14176
15185
  as: "span",
@@ -14183,7 +15192,7 @@ function ITTopBar({
14183
15192
  ]
14184
15193
  }
14185
15194
  ),
14186
- /* @__PURE__ */ jsxs55(
15195
+ /* @__PURE__ */ jsxs56(
14187
15196
  "div",
14188
15197
  {
14189
15198
  ref: userMenuRef,
@@ -14196,15 +15205,15 @@ function ITTopBar({
14196
15205
  border: "1px solid var(--it-topbar-user-dropdown-border, #f1f5f9)"
14197
15206
  },
14198
15207
  children: [
14199
- /* @__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: [
14200
- /* @__PURE__ */ jsx77(ITText, { as: "span", className: "block font-bold text-[0.9rem]", style: { color: "var(--it-topbar-user-text, #0f172a)" }, children: userMenu.userName }),
14201
- /* @__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 })
14202
15211
  ] }),
14203
- /* @__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) => {
14204
15213
  const isDestructive = m.label.toLowerCase().includes("salir") || m.label.toLowerCase().includes("cerrar") || m.label.toLowerCase().includes("logout");
14205
- return /* @__PURE__ */ jsxs55("li", { className: "px-2", children: [
14206
- i === userMenu.menuItems.length - 1 && isDestructive && i > 0 && /* @__PURE__ */ jsx77("div", { className: "h-px bg-slate-100 my-1 mx-2" }),
14207
- /* @__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(
14208
15217
  "button",
14209
15218
  {
14210
15219
  onClick: () => {
@@ -14219,7 +15228,7 @@ function ITTopBar({
14219
15228
  onMouseLeave: (e) => {
14220
15229
  e.currentTarget.style.backgroundColor = "transparent";
14221
15230
  },
14222
- children: /* @__PURE__ */ jsx77(ITText, { as: "span", children: m.label })
15231
+ children: /* @__PURE__ */ jsx78(ITText, { as: "span", children: m.label })
14223
15232
  }
14224
15233
  )
14225
15234
  ] }, i);
@@ -14235,7 +15244,7 @@ function ITTopBar({
14235
15244
  }
14236
15245
 
14237
15246
  // src/components/templates/layout/layout.tsx
14238
- import { jsx as jsx78, jsxs as jsxs56 } from "react/jsx-runtime";
15247
+ import { jsx as jsx79, jsxs as jsxs57 } from "react/jsx-runtime";
14239
15248
  function ITLayout({
14240
15249
  topBar,
14241
15250
  sidebar,
@@ -14244,8 +15253,8 @@ function ITLayout({
14244
15253
  contentClassName = "",
14245
15254
  sidebarFullHeight = false
14246
15255
  }) {
14247
- const [internalCollapsed, setInternalCollapsed] = useState39(true);
14248
- const [mobileSidebarOpen, setMobileSidebarOpen] = useState39(false);
15256
+ const [internalCollapsed, setInternalCollapsed] = useState42(true);
15257
+ const [mobileSidebarOpen, setMobileSidebarOpen] = useState42(false);
14249
15258
  const flat = useITFlatAppearance();
14250
15259
  const isControlled = sidebar.isCollapsed !== void 0;
14251
15260
  const desktopCollapsed = isControlled ? sidebar.isCollapsed : internalCollapsed;
@@ -14259,7 +15268,7 @@ function ITLayout({
14259
15268
  else setMobileSidebarOpen((v) => !v);
14260
15269
  };
14261
15270
  const brand = sidebarFullHeight ? sidebar.brand ?? { logo: topBar.logo, text: topBar.logoText } : sidebar.brand;
14262
- const topBarNode = /* @__PURE__ */ jsx78(
15271
+ const topBarNode = /* @__PURE__ */ jsx79(
14263
15272
  ITTopBar,
14264
15273
  {
14265
15274
  ...topBar,
@@ -14272,9 +15281,9 @@ function ITLayout({
14272
15281
  const desktopSidebar = (
14273
15282
  // Full-height: the sidebar sits beside the top bar, so it needs to win the
14274
15283
  // stacking order when the collapsed rail expands over the content on hover.
14275
- /* @__PURE__ */ jsxs56("div", { className: `hidden lg:block relative h-full ${sidebarFullHeight ? "z-50" : "z-40"}`, children: [
14276
- /* @__PURE__ */ jsx78("div", { className: `${reservedWidth} h-full flex-shrink-0` }),
14277
- /* @__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(
14278
15287
  ITSidebar,
14279
15288
  {
14280
15289
  ...sidebar,
@@ -14287,17 +15296,17 @@ function ITLayout({
14287
15296
  ) })
14288
15297
  ] })
14289
15298
  );
14290
- const mobileSidebar = mobileSidebarOpen && /* @__PURE__ */ jsx78(
15299
+ const mobileSidebar = mobileSidebarOpen && /* @__PURE__ */ jsx79(
14291
15300
  "div",
14292
15301
  {
14293
15302
  className: "lg:hidden fixed inset-0 z-[40] transition-opacity duration-300 backdrop-blur-sm bg-black/40",
14294
15303
  onClick: () => setMobileSidebarOpen(false),
14295
- children: /* @__PURE__ */ jsx78(
15304
+ children: /* @__PURE__ */ jsx79(
14296
15305
  "div",
14297
15306
  {
14298
15307
  className: "h-full w-fit flex transform transition-transform duration-300 ease-[cubic-bezier(0.2,0,0,1)]",
14299
15308
  onClick: (e) => e.stopPropagation(),
14300
- children: /* @__PURE__ */ jsx78(
15309
+ children: /* @__PURE__ */ jsx79(
14301
15310
  ITSidebar,
14302
15311
  {
14303
15312
  ...sidebar,
@@ -14314,16 +15323,16 @@ function ITLayout({
14314
15323
  )
14315
15324
  }
14316
15325
  );
14317
- 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 }) });
14318
15327
  if (sidebarFullHeight) {
14319
- return /* @__PURE__ */ jsxs56(
15328
+ return /* @__PURE__ */ jsxs57(
14320
15329
  "div",
14321
15330
  {
14322
15331
  className: `flex h-screen overflow-hidden w-full relative ${className}`,
14323
15332
  style: { backgroundColor: layoutTokens.backgroundColor },
14324
15333
  children: [
14325
15334
  desktopSidebar,
14326
- /* @__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: [
14327
15336
  topBarNode,
14328
15337
  main
14329
15338
  ] }),
@@ -14332,9 +15341,9 @@ function ITLayout({
14332
15341
  }
14333
15342
  );
14334
15343
  }
14335
- 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: [
14336
15345
  topBarNode,
14337
- /* @__PURE__ */ jsxs56(
15346
+ /* @__PURE__ */ jsxs57(
14338
15347
  "div",
14339
15348
  {
14340
15349
  className: "flex flex-1 overflow-hidden relative",
@@ -14351,9 +15360,9 @@ function ITLayout({
14351
15360
 
14352
15361
  // src/components/molecules/stepper/stepper.tsx
14353
15362
  import clsx56 from "clsx";
14354
- 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";
14355
15364
  import { FaChevronLeft as FaChevronLeft4, FaChevronRight as FaChevronRight7, FaCheck as FaCheck6 } from "react-icons/fa";
14356
- import { jsx as jsx79, jsxs as jsxs57 } from "react/jsx-runtime";
15365
+ import { jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
14357
15366
  function ITStepper({
14358
15367
  steps,
14359
15368
  currentStep,
@@ -14369,15 +15378,15 @@ function ITStepper({
14369
15378
  color = "primary"
14370
15379
  }) {
14371
15380
  const { t } = useITTranslation();
14372
- const [direction, setDirection] = useState40("next");
15381
+ const [direction, setDirection] = useState43("next");
14373
15382
  const contentRef = useRef25(null);
14374
15383
  const progressRef = useRef25(null);
14375
15384
  const isThemeColor = color in theme.colors;
14376
15385
  const resolvedColor = isThemeColor ? theme.colors[color][500] : color;
14377
- useEffect20(() => {
15386
+ useEffect21(() => {
14378
15387
  onStepChange?.(currentStep);
14379
15388
  }, [currentStep, onStepChange]);
14380
- useEffect20(() => {
15389
+ useEffect21(() => {
14381
15390
  const pct = currentStep / Math.max(1, steps.length - 1) * 100;
14382
15391
  if (progressRef.current) {
14383
15392
  progressRef.current.style.width = `${pct}%`;
@@ -14421,23 +15430,23 @@ function ITStepper({
14421
15430
  const renderStepContent = (index, isCompleted) => {
14422
15431
  const step = steps[index];
14423
15432
  if (isCompleted) {
14424
- return /* @__PURE__ */ jsx79(FaCheck6, { className: "w-4 h-4" });
15433
+ return /* @__PURE__ */ jsx80(FaCheck6, { className: "w-4 h-4" });
14425
15434
  }
14426
15435
  if (step.icon && useIcons) {
14427
- 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 });
14428
15437
  }
14429
- 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 });
14430
15439
  };
14431
- return /* @__PURE__ */ jsxs57("div", { className: clsx56("w-full max-w-5xl mx-auto px-4", containerClassName), children: [
14432
- /* @__PURE__ */ jsxs57("div", { className: "relative mb-8", children: [
14433
- /* @__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(
14434
15443
  "div",
14435
15444
  {
14436
15445
  className: "absolute left-6 right-6 top-5 h-1 bg-secondary-200 rounded-full z-0",
14437
15446
  "aria-hidden": true
14438
15447
  }
14439
15448
  ),
14440
- /* @__PURE__ */ jsx79(
15449
+ /* @__PURE__ */ jsx80(
14441
15450
  "div",
14442
15451
  {
14443
15452
  ref: progressRef,
@@ -14445,11 +15454,11 @@ function ITStepper({
14445
15454
  "aria-hidden": true
14446
15455
  }
14447
15456
  ),
14448
- /* @__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) => {
14449
15458
  const isActive = idx === currentStep;
14450
15459
  const isCompleted = idx < currentStep;
14451
15460
  const hasIcon = step.icon && useIcons;
14452
- return /* @__PURE__ */ jsx79(
15461
+ return /* @__PURE__ */ jsx80(
14453
15462
  "button",
14454
15463
  {
14455
15464
  type: "button",
@@ -14459,8 +15468,8 @@ function ITStepper({
14459
15468
  "aria-label": t("stepper.stepAria", { n: idx + 1, label: step.label }),
14460
15469
  className: "flex-1 group",
14461
15470
  title: step.label,
14462
- children: /* @__PURE__ */ jsxs57("div", { className: "flex flex-col items-center", children: [
14463
- /* @__PURE__ */ jsx79(
15471
+ children: /* @__PURE__ */ jsxs58("div", { className: "flex flex-col items-center", children: [
15472
+ /* @__PURE__ */ jsx80(
14464
15473
  "div",
14465
15474
  {
14466
15475
  className: clsx56(
@@ -14474,7 +15483,7 @@ function ITStepper({
14474
15483
  children: renderStepContent(idx, isCompleted)
14475
15484
  }
14476
15485
  ),
14477
- /* @__PURE__ */ jsx79(
15486
+ /* @__PURE__ */ jsx80(
14478
15487
  ITText,
14479
15488
  {
14480
15489
  as: "span",
@@ -14492,7 +15501,7 @@ function ITStepper({
14492
15501
  );
14493
15502
  }) })
14494
15503
  ] }),
14495
- /* @__PURE__ */ jsx79(
15504
+ /* @__PURE__ */ jsx80(
14496
15505
  "div",
14497
15506
  {
14498
15507
  ref: contentRef,
@@ -14508,32 +15517,32 @@ function ITStepper({
14508
15517
  children: steps[currentStep].content
14509
15518
  }
14510
15519
  ),
14511
- /* @__PURE__ */ jsxs57("div", { className: "flex justify-between items-center mt-6", children: [
14512
- /* @__PURE__ */ jsx79(
15520
+ /* @__PURE__ */ jsxs58("div", { className: "flex justify-between items-center mt-6", children: [
15521
+ /* @__PURE__ */ jsx80(
14513
15522
  ITButton,
14514
15523
  {
14515
15524
  variant: "outlined",
14516
15525
  color: "secondary",
14517
15526
  disabled: currentStep === 0,
14518
15527
  onClick: prevStep,
14519
- children: /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
14520
- /* @__PURE__ */ jsx79(FaChevronLeft4, {}),
14521
- /* @__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") })
14522
15531
  ] })
14523
15532
  }
14524
15533
  ),
14525
- /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-3", children: [
14526
- /* @__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 }) }),
14527
- /* @__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(
14528
15537
  ITButton,
14529
15538
  {
14530
15539
  variant: "solid",
14531
15540
  color,
14532
15541
  disabled: disableNext,
14533
15542
  onClick: nextStep,
14534
- children: /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
14535
- /* @__PURE__ */ jsx79(ITText, { as: "span", children: currentStep === steps.length - 1 ? t("common.finish") : t("common.next") }),
14536
- 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, {})
14537
15546
  ] })
14538
15547
  }
14539
15548
  )
@@ -14543,7 +15552,7 @@ function ITStepper({
14543
15552
  }
14544
15553
 
14545
15554
  // src/components/theme-provider/themeProvider.tsx
14546
- 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";
14547
15556
  import { MdPalette, MdClose, MdRefresh } from "react-icons/md";
14548
15557
 
14549
15558
  // src/components/theme-provider/themePresets.ts
@@ -14721,7 +15730,7 @@ var PRESETS = [
14721
15730
  ];
14722
15731
 
14723
15732
  // src/components/theme-provider/themeProvider.tsx
14724
- import { jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
15733
+ import { jsx as jsx81, jsxs as jsxs59 } from "react/jsx-runtime";
14725
15734
  var STORAGE_KEY = "it-theme-palette";
14726
15735
  var SHADOW_LEVELS = {
14727
15736
  0: {
@@ -14824,7 +15833,7 @@ function ITThemeProvider({
14824
15833
  appearance = "soft"
14825
15834
  }) {
14826
15835
  const { t } = useITTranslation();
14827
- const [palette2, setPaletteState] = useState41(() => {
15836
+ const [palette2, setPaletteState] = useState44(() => {
14828
15837
  const basePalette = {
14829
15838
  ...DEFAULT_PALETTE,
14830
15839
  ...theme2,
@@ -14850,8 +15859,8 @@ function ITThemeProvider({
14850
15859
  }
14851
15860
  return basePalette;
14852
15861
  });
14853
- const [isOpen, setIsOpen] = useState41(false);
14854
- const [customPresets, setCustomPresets] = useState41(() => {
15862
+ const [isOpen, setIsOpen] = useState44(false);
15863
+ const [customPresets, setCustomPresets] = useState44(() => {
14855
15864
  try {
14856
15865
  const saved = localStorage.getItem("it-theme-custom-presets");
14857
15866
  return saved ? JSON.parse(saved) : [];
@@ -14860,8 +15869,8 @@ function ITThemeProvider({
14860
15869
  return [];
14861
15870
  }
14862
15871
  });
14863
- const [newPresetName, setNewPresetName] = useState41("");
14864
- const [isSavingPreset, setIsSavingPreset] = useState41(false);
15872
+ const [newPresetName, setNewPresetName] = useState44("");
15873
+ const [isSavingPreset, setIsSavingPreset] = useState44(false);
14865
15874
  const handleSavePreset = () => {
14866
15875
  if (!newPresetName.trim()) return;
14867
15876
  const newPreset = {
@@ -14880,8 +15889,8 @@ function ITThemeProvider({
14880
15889
  setCustomPresets(updated);
14881
15890
  localStorage.setItem("it-theme-custom-presets", JSON.stringify(updated));
14882
15891
  };
14883
- const [resolvedTheme, setResolvedTheme] = useState41("light");
14884
- const [darkModeMode, setDarkModeMode] = useState41(
15892
+ const [resolvedTheme, setResolvedTheme] = useState44("light");
15893
+ const [darkModeMode, setDarkModeMode] = useState44(
14885
15894
  () => {
14886
15895
  const saved = localStorage.getItem("it-theme-dark-mode");
14887
15896
  if (saved === "light" || saved === "dark" || saved === "system") {
@@ -14890,7 +15899,7 @@ function ITThemeProvider({
14890
15899
  return "system";
14891
15900
  }
14892
15901
  );
14893
- useEffect21(() => {
15902
+ useEffect22(() => {
14894
15903
  localStorage.setItem("it-theme-dark-mode", darkModeMode);
14895
15904
  const applyDarkMode = (isDark) => {
14896
15905
  if (isDark) {
@@ -14915,7 +15924,7 @@ function ITThemeProvider({
14915
15924
  applyDarkMode(darkModeMode === "dark");
14916
15925
  }
14917
15926
  }, [darkModeMode]);
14918
- useEffect21(() => {
15927
+ useEffect22(() => {
14919
15928
  if (!showFab) {
14920
15929
  setPaletteState({
14921
15930
  ...DEFAULT_PALETTE,
@@ -14972,7 +15981,7 @@ function ITThemeProvider({
14972
15981
  surfaceStyle?.remove();
14973
15982
  };
14974
15983
  }, [radius, shadow]);
14975
- useEffect21(() => {
15984
+ useEffect22(() => {
14976
15985
  const injectStyles = (obj, prefix = "") => {
14977
15986
  Object.entries(obj).forEach(([key, val]) => {
14978
15987
  if (typeof val === "object" && val !== null) {
@@ -16126,14 +17135,14 @@ function ITThemeProvider({
16126
17135
  const isNested = colorKey.includes(".");
16127
17136
  const label = isNested ? colorKey.split(".")[1] : colorKey;
16128
17137
  const value = getNestedValue3(palette2, colorKey);
16129
- return /* @__PURE__ */ jsxs58(
17138
+ return /* @__PURE__ */ jsxs59(
16130
17139
  "div",
16131
17140
  {
16132
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",
16133
17142
  children: [
16134
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [
16135
- /* @__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: [
16136
- /* @__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(
16137
17146
  "input",
16138
17147
  {
16139
17148
  type: "color",
@@ -16142,23 +17151,23 @@ function ITThemeProvider({
16142
17151
  className: "absolute inset-0 opacity-0 cursor-pointer w-full h-full"
16143
17152
  }
16144
17153
  ),
16145
- /* @__PURE__ */ jsx80("div", { className: "w-full h-full", style: { backgroundColor: value } })
17154
+ /* @__PURE__ */ jsx81("div", { className: "w-full h-full", style: { backgroundColor: value } })
16146
17155
  ] }),
16147
- /* @__PURE__ */ jsxs58("div", { className: "flex flex-col min-w-0", children: [
16148
- /* @__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() }),
16149
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-2 mt-0.5", children: [
16150
- /* @__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(
16151
17160
  "span",
16152
17161
  {
16153
17162
  className: "w-3 h-3 rounded-full border border-slate-200 dark:border-slate-600",
16154
17163
  style: { backgroundColor: value }
16155
17164
  }
16156
17165
  ),
16157
- /* @__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 })
16158
17167
  ] })
16159
17168
  ] })
16160
17169
  ] }),
16161
- /* @__PURE__ */ jsx80(
17170
+ /* @__PURE__ */ jsx81(
16162
17171
  "input",
16163
17172
  {
16164
17173
  type: "text",
@@ -16177,14 +17186,14 @@ function ITThemeProvider({
16177
17186
  isCustom
16178
17187
  }) => {
16179
17188
  const isSelected = JSON.stringify(preset.colors) === JSON.stringify(palette2);
16180
- return /* @__PURE__ */ jsxs58(
17189
+ return /* @__PURE__ */ jsxs59(
16181
17190
  "button",
16182
17191
  {
16183
17192
  type: "button",
16184
17193
  onClick: () => applyPreset(preset.colors),
16185
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"}`,
16186
17195
  children: [
16187
- isCustom && /* @__PURE__ */ jsx80(
17196
+ isCustom && /* @__PURE__ */ jsx81(
16188
17197
  "span",
16189
17198
  {
16190
17199
  onClick: (e) => {
@@ -16193,11 +17202,11 @@ function ITThemeProvider({
16193
17202
  },
16194
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",
16195
17204
  title: t("themeProvider.designer.deletePreset"),
16196
- children: /* @__PURE__ */ jsx80(MdClose, { size: 12 })
17205
+ children: /* @__PURE__ */ jsx81(MdClose, { size: 12 })
16197
17206
  }
16198
17207
  ),
16199
- /* @__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 }),
16200
- /* @__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(
16201
17210
  "span",
16202
17211
  {
16203
17212
  className: "w-3 h-3 rounded-full border border-black/10",
@@ -16209,7 +17218,7 @@ function ITThemeProvider({
16209
17218
  }
16210
17219
  );
16211
17220
  };
16212
- return /* @__PURE__ */ jsxs58(
17221
+ return /* @__PURE__ */ jsxs59(
16213
17222
  ITThemeContext.Provider,
16214
17223
  {
16215
17224
  value: {
@@ -16226,28 +17235,28 @@ function ITThemeProvider({
16226
17235
  },
16227
17236
  children: [
16228
17237
  children,
16229
- showFab && /* @__PURE__ */ jsx80(
17238
+ showFab && /* @__PURE__ */ jsx81(
16230
17239
  "button",
16231
17240
  {
16232
17241
  onClick: () => setIsOpen((prev) => !prev),
16233
17242
  className: "it-theme-fab it-theme-bounce",
16234
17243
  style: { backgroundColor: "var(--color-primary)" },
16235
17244
  "aria-label": t("themeProvider.fab.ariaLabel"),
16236
- children: /* @__PURE__ */ jsx80(MdPalette, { size: 28 })
17245
+ children: /* @__PURE__ */ jsx81(MdPalette, { size: 28 })
16237
17246
  }
16238
17247
  ),
16239
- showFab && /* @__PURE__ */ jsx80(
17248
+ showFab && /* @__PURE__ */ jsx81(
16240
17249
  ITDialog,
16241
17250
  {
16242
17251
  isOpen,
16243
17252
  onClose: () => setIsOpen(false),
16244
17253
  title: t("themeProvider.designer.title"),
16245
17254
  useFormHeader: true,
16246
- children: /* @__PURE__ */ jsxs58("div", { className: "flex gap-6 h-[580px]", children: [
16247
- /* @__PURE__ */ jsxs58("div", { className: "w-64 flex-shrink-0 flex flex-col gap-5 overflow-y-auto pr-1", children: [
16248
- /* @__PURE__ */ jsxs58("div", { children: [
16249
- /* @__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") }),
16250
- /* @__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(
16251
17260
  ITSegmentedControl,
16252
17261
  {
16253
17262
  options: [
@@ -16261,16 +17270,16 @@ function ITThemeProvider({
16261
17270
  }
16262
17271
  )
16263
17272
  ] }),
16264
- /* @__PURE__ */ jsxs58("div", { children: [
16265
- /* @__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") }) }),
16266
- /* @__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)) })
16267
17276
  ] }),
16268
- customPresets.length > 0 && /* @__PURE__ */ jsxs58("div", { children: [
16269
- /* @__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") }),
16270
- /* @__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)) })
16271
17280
  ] }),
16272
- 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: [
16273
- /* @__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(
16274
17283
  ITInput,
16275
17284
  {
16276
17285
  name: "presetName",
@@ -16288,8 +17297,8 @@ function ITThemeProvider({
16288
17297
  }
16289
17298
  }
16290
17299
  ),
16291
- /* @__PURE__ */ jsxs58("div", { className: "flex gap-2", children: [
16292
- /* @__PURE__ */ jsx80(
17300
+ /* @__PURE__ */ jsxs59("div", { className: "flex gap-2", children: [
17301
+ /* @__PURE__ */ jsx81(
16293
17302
  ITButton,
16294
17303
  {
16295
17304
  label: t("themeProvider.designer.save"),
@@ -16300,7 +17309,7 @@ function ITThemeProvider({
16300
17309
  className: "flex-1"
16301
17310
  }
16302
17311
  ),
16303
- /* @__PURE__ */ jsx80(
17312
+ /* @__PURE__ */ jsx81(
16304
17313
  ITButton,
16305
17314
  {
16306
17315
  label: t("themeProvider.designer.cancelSave"),
@@ -16314,31 +17323,31 @@ function ITThemeProvider({
16314
17323
  )
16315
17324
  ] })
16316
17325
  ] }),
16317
- !isSavingPreset && /* @__PURE__ */ jsx80(
17326
+ !isSavingPreset && /* @__PURE__ */ jsx81(
16318
17327
  ITButton,
16319
17328
  {
16320
17329
  variant: "outlined",
16321
- icon: /* @__PURE__ */ jsx80(MdPalette, { size: 14 }),
17330
+ icon: /* @__PURE__ */ jsx81(MdPalette, { size: 14 }),
16322
17331
  label: t("themeProvider.designer.saveCurrent"),
16323
17332
  onClick: () => setIsSavingPreset(true),
16324
17333
  size: "sm"
16325
17334
  }
16326
17335
  ),
16327
- /* @__PURE__ */ jsx80(
17336
+ /* @__PURE__ */ jsx81(
16328
17337
  ITButton,
16329
17338
  {
16330
17339
  variant: "outlined",
16331
17340
  color: "danger",
16332
- icon: /* @__PURE__ */ jsx80(MdRefresh, { size: 14 }),
17341
+ icon: /* @__PURE__ */ jsx81(MdRefresh, { size: 14 }),
16333
17342
  label: t("themeProvider.designer.reset"),
16334
17343
  onClick: resetTheme,
16335
17344
  size: "sm"
16336
17345
  }
16337
17346
  )
16338
17347
  ] }),
16339
- /* @__PURE__ */ jsx80(ITDivider, { orientation: "vertical" }),
16340
- /* @__PURE__ */ jsxs58("div", { className: "flex-1 flex flex-col min-w-0", children: [
16341
- /* @__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(
16342
17351
  tabs_default,
16343
17352
  {
16344
17353
  variant: "pill",
@@ -16346,7 +17355,7 @@ function ITThemeProvider({
16346
17355
  {
16347
17356
  id: "brand",
16348
17357
  label: t("themeProvider.tabs.brand"),
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: [
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: [
16350
17359
  "primary",
16351
17360
  "secondary",
16352
17361
  "ternary",
@@ -16355,35 +17364,35 @@ function ITThemeProvider({
16355
17364
  "info",
16356
17365
  "alert",
16357
17366
  "warning"
16358
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17367
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16359
17368
  },
16360
17369
  {
16361
17370
  id: "layout",
16362
17371
  label: t("themeProvider.tabs.layout"),
16363
- 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: [
16364
17373
  "layout.sidebarBg",
16365
17374
  "layout.sidebarText",
16366
17375
  "layout.navbarBg",
16367
17376
  "layout.navbarText"
16368
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17377
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16369
17378
  },
16370
17379
  {
16371
17380
  id: "tables",
16372
17381
  label: t("themeProvider.tabs.tables"),
16373
- 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: [
16374
17383
  "table.headerBg",
16375
17384
  "table.headerText",
16376
17385
  "table.rowBg",
16377
17386
  "table.rowText",
16378
17387
  "table.rowHover"
16379
- ].map((key) => /* @__PURE__ */ jsx80(ColorRow, { colorKey: key }, key)) })
17388
+ ].map((key) => /* @__PURE__ */ jsx81(ColorRow, { colorKey: key }, key)) })
16380
17389
  }
16381
17390
  ]
16382
17391
  }
16383
17392
  ),
16384
- /* @__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: [
16385
- /* @__PURE__ */ jsx80(ITText, { as: "p", className: "text-[11px] text-slate-400 mr-auto", children: t("themeProvider.designer.autosave") }),
16386
- /* @__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(
16387
17396
  ITButton,
16388
17397
  {
16389
17398
  label: t("themeProvider.designer.close"),
@@ -16441,7 +17450,7 @@ export {
16441
17450
  dropfile_default as ITDropfile,
16442
17451
  ITEmptyState,
16443
17452
  ITField,
16444
- ITFlex,
17453
+ flex_default as ITFlex,
16445
17454
  ITFormBuilder,
16446
17455
  ITFormHeader,
16447
17456
  ITGrid,
@@ -16478,7 +17487,7 @@ export {
16478
17487
  ITTable,
16479
17488
  tabs_default as ITTabs,
16480
17489
  ITText,
16481
- ITTextarea,
17490
+ textarea_default as ITTextarea,
16482
17491
  ITThemeProvider,
16483
17492
  ITTimePicker,
16484
17493
  ITToast,
@@ -16490,13 +17499,16 @@ export {
16490
17499
  auditTree,
16491
17500
  axzyCatalog,
16492
17501
  axzyCatalogTypes,
17502
+ buildNavigationTree,
16493
17503
  buildVocabularyContract,
16494
17504
  countPendingNodes,
17505
+ createBindingResolver,
16495
17506
  createCatalog,
16496
17507
  createLimitTracker,
16497
17508
  createValidationSchema,
16498
17509
  en_default as enMessages,
16499
17510
  es_default as esMessages,
17511
+ flattenRoutes,
16500
17512
  formatPath,
16501
17513
  formatVocabularyForPrompt,
16502
17514
  getCatalogEntry,
@@ -16507,7 +17519,10 @@ export {
16507
17519
  isLightColor,
16508
17520
  isNodePending,
16509
17521
  issue,
17522
+ joinRoutePath,
17523
+ matchRoute,
16510
17524
  migrateSchema,
17525
+ navContainsRoute,
16511
17526
  parsePartialSchema,
16512
17527
  parsePath,
16513
17528
  propPath,
@@ -16517,6 +17532,7 @@ export {
16517
17532
  resolveCssColor,
16518
17533
  resolveLimits,
16519
17534
  resolveNode,
17535
+ routeHref,
16520
17536
  useClickOutside_default as useClickOutside,
16521
17537
  useDebouncedSearch,
16522
17538
  useEditableRow,
@@ -16526,7 +17542,9 @@ export {
16526
17542
  useITThemeSafe,
16527
17543
  useITTranslation,
16528
17544
  useJsonRender_default as useJsonRender,
17545
+ useSchemaStream,
16529
17546
  useTableState,
17547
+ validateRoutes,
16530
17548
  validateSchema
16531
17549
  };
16532
17550
  //# sourceMappingURL=index.js.map