@arqel-dev/ui 0.15.0 → 0.15.1

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 (95) hide show
  1. package/README.md +1 -1
  2. package/dist/{AreaChart-NMQ2RQGA.js → AreaChart-JAZ6LUYG.js} +8 -4
  3. package/dist/AreaChart-JAZ6LUYG.js.map +1 -0
  4. package/dist/ArqelCreatePage-UZAHV4DK.js +8 -0
  5. package/dist/{ArqelCreatePage-MV4JN2MO.js.map → ArqelCreatePage-UZAHV4DK.js.map} +1 -1
  6. package/dist/ArqelDashboardPage-Z5R4XSH4.js +6 -0
  7. package/dist/{ArqelDashboardPage-QK3BYVK3.js.map → ArqelDashboardPage-Z5R4XSH4.js.map} +1 -1
  8. package/dist/ArqelEditPage-RRYFYOTC.js +8 -0
  9. package/dist/{ArqelShowPage-5WWUSYC7.js.map → ArqelEditPage-RRYFYOTC.js.map} +1 -1
  10. package/dist/ArqelIndexPage-RGZWKKAX.js +12 -0
  11. package/dist/{ArqelIndexPage-R6JL5KOH.js.map → ArqelIndexPage-RGZWKKAX.js.map} +1 -1
  12. package/dist/ArqelShowPage-TVCJAV2F.js +6 -0
  13. package/dist/{ArqelEditPage-7J3IS2BR.js.map → ArqelShowPage-TVCJAV2F.js.map} +1 -1
  14. package/dist/{BarChart-KLHKTLO2.js → BarChart-E52NJSJE.js} +8 -4
  15. package/dist/BarChart-E52NJSJE.js.map +1 -0
  16. package/dist/{DonutChart-L56R4QF2.js → DonutChart-IGSF4LEB.js} +3 -3
  17. package/dist/{DonutChart-L56R4QF2.js.map → DonutChart-IGSF4LEB.js.map} +1 -1
  18. package/dist/{FormRenderer-BJBRIkfH.d.ts → FormRenderer-By8fZp4t.d.ts} +2 -0
  19. package/dist/{LineChart-GHMPHFZZ.js → LineChart-RRPGAZON.js} +8 -4
  20. package/dist/LineChart-RRPGAZON.js.map +1 -0
  21. package/dist/PieChart-SGN7V5LQ.js +4 -0
  22. package/dist/{PieChart-T2VQOFPP.js.map → PieChart-SGN7V5LQ.js.map} +1 -1
  23. package/dist/{RadarChart-CSWR5AO7.js → RadarChart-3AOM736J.js} +8 -4
  24. package/dist/RadarChart-3AOM736J.js.map +1 -0
  25. package/dist/action.js +2 -2
  26. package/dist/{chunk-FP5R6WED.js → chunk-2JUWLJ3K.js} +21 -13
  27. package/dist/chunk-2JUWLJ3K.js.map +1 -0
  28. package/dist/{chunk-BJER6TOI.js → chunk-3VSDQCFO.js} +3 -3
  29. package/dist/{chunk-BJER6TOI.js.map → chunk-3VSDQCFO.js.map} +1 -1
  30. package/dist/{chunk-N5U2BB6T.js → chunk-4VWNBMMA.js} +8 -6
  31. package/dist/chunk-4VWNBMMA.js.map +1 -0
  32. package/dist/{chunk-ZAM5TUPP.js → chunk-CMNZLA32.js} +60 -25
  33. package/dist/chunk-CMNZLA32.js.map +1 -0
  34. package/dist/{chunk-CVAMCRLL.js → chunk-EG2DASKR.js} +8 -4
  35. package/dist/chunk-EG2DASKR.js.map +1 -0
  36. package/dist/{chunk-DSULVRB6.js → chunk-GJ2FKAOM.js} +5 -3
  37. package/dist/chunk-GJ2FKAOM.js.map +1 -0
  38. package/dist/{chunk-FV7RESKL.js → chunk-HNUUZEOL.js} +28 -16
  39. package/dist/chunk-HNUUZEOL.js.map +1 -0
  40. package/dist/{chunk-37FLEB4N.js → chunk-IO6RMVUF.js} +8 -4
  41. package/dist/chunk-IO6RMVUF.js.map +1 -0
  42. package/dist/{chunk-4I5S6MH3.js → chunk-LLANMODS.js} +4 -4
  43. package/dist/{chunk-4I5S6MH3.js.map → chunk-LLANMODS.js.map} +1 -1
  44. package/dist/{chunk-N6WLCHQE.js → chunk-Q7WGPKUN.js} +6 -4
  45. package/dist/chunk-Q7WGPKUN.js.map +1 -0
  46. package/dist/{chunk-AZICSFBA.js → chunk-S5UNPCMQ.js} +112 -38
  47. package/dist/chunk-S5UNPCMQ.js.map +1 -0
  48. package/dist/{chunk-MTNFFSVA.js → chunk-SK6H7ARE.js} +5 -3
  49. package/dist/chunk-SK6H7ARE.js.map +1 -0
  50. package/dist/{chunk-PSPJA5U6.js → chunk-WMOBLT3Z.js} +10 -5
  51. package/dist/chunk-WMOBLT3Z.js.map +1 -0
  52. package/dist/{chunk-C5H44NSP.js → chunk-WZRPGPLH.js} +10 -5
  53. package/dist/chunk-WZRPGPLH.js.map +1 -0
  54. package/dist/{chunk-UXN67E5L.js → chunk-YQ6KXR3U.js} +8 -10
  55. package/dist/chunk-YQ6KXR3U.js.map +1 -0
  56. package/dist/{chunk-HSDZM4AM.js → chunk-YYQ45W25.js} +37 -24
  57. package/dist/chunk-YYQ45W25.js.map +1 -0
  58. package/dist/flash.js +1 -1
  59. package/dist/form.d.ts +3 -1
  60. package/dist/form.js +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.js +9 -9
  63. package/dist/pages.js +16 -16
  64. package/dist/palette.js +1 -1
  65. package/dist/resource.js +2 -2
  66. package/dist/shell.js +8 -4
  67. package/dist/shell.js.map +1 -1
  68. package/dist/table.js +1 -1
  69. package/dist/utility.js +1 -1
  70. package/dist/widgets.js +2 -2
  71. package/package.json +6 -6
  72. package/dist/AreaChart-NMQ2RQGA.js.map +0 -1
  73. package/dist/ArqelCreatePage-MV4JN2MO.js +0 -8
  74. package/dist/ArqelDashboardPage-QK3BYVK3.js +0 -6
  75. package/dist/ArqelEditPage-7J3IS2BR.js +0 -8
  76. package/dist/ArqelIndexPage-R6JL5KOH.js +0 -12
  77. package/dist/ArqelShowPage-5WWUSYC7.js +0 -6
  78. package/dist/BarChart-KLHKTLO2.js.map +0 -1
  79. package/dist/LineChart-GHMPHFZZ.js.map +0 -1
  80. package/dist/PieChart-T2VQOFPP.js +0 -4
  81. package/dist/RadarChart-CSWR5AO7.js.map +0 -1
  82. package/dist/chunk-37FLEB4N.js.map +0 -1
  83. package/dist/chunk-AZICSFBA.js.map +0 -1
  84. package/dist/chunk-C5H44NSP.js.map +0 -1
  85. package/dist/chunk-CVAMCRLL.js.map +0 -1
  86. package/dist/chunk-DSULVRB6.js.map +0 -1
  87. package/dist/chunk-FP5R6WED.js.map +0 -1
  88. package/dist/chunk-FV7RESKL.js.map +0 -1
  89. package/dist/chunk-HSDZM4AM.js.map +0 -1
  90. package/dist/chunk-MTNFFSVA.js.map +0 -1
  91. package/dist/chunk-N5U2BB6T.js.map +0 -1
  92. package/dist/chunk-N6WLCHQE.js.map +0 -1
  93. package/dist/chunk-PSPJA5U6.js.map +0 -1
  94. package/dist/chunk-UXN67E5L.js.map +0 -1
  95. package/dist/chunk-ZAM5TUPP.js.map +0 -1
@@ -1,4 +1,6 @@
1
1
  import { colorFor } from './chunk-L3JBBN4H.js';
2
+ import { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';
3
+ import { useMemo } from 'react';
2
4
  import { ResponsiveContainer, PieChart as PieChart$1, Pie, Cell, Tooltip, Legend } from 'recharts';
3
5
  import { jsx, jsxs } from 'react/jsx-runtime';
4
6
 
@@ -9,9 +11,12 @@ function PieChart({
9
11
  innerRadius = 0,
10
12
  testId = "chart-pie"
11
13
  }) {
14
+ const locale = useArqelLocale();
15
+ const t = useArqelTranslations();
16
+ const nf = useMemo(() => new Intl.NumberFormat(locale), [locale]);
12
17
  const first = chartData.datasets[0];
13
18
  const slices = (first?.data ?? []).map((value, i) => ({
14
- name: chartData.labels[i] ?? `Slice ${i + 1}`,
19
+ name: chartData.labels[i] ?? t("arqel.chart.slice_fallback", "Slice :number", { number: i + 1 }),
15
20
  value
16
21
  }));
17
22
  return /* @__PURE__ */ jsx("div", { "data-testid": testId, style: { width: "100%", height }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart$1, { children: [
@@ -23,15 +28,15 @@ function PieChart({
23
28
  nameKey: "name",
24
29
  innerRadius,
25
30
  outerRadius: "80%",
26
- label: true,
31
+ label: (entry) => nf.format(Number(entry.value)),
27
32
  children: slices.map((slice, i) => /* @__PURE__ */ jsx(Cell, { fill: colorFor(first ?? { label: "", data: [] }, i) }, slice.name))
28
33
  }
29
34
  ),
30
- /* @__PURE__ */ jsx(Tooltip, {}),
35
+ /* @__PURE__ */ jsx(Tooltip, { formatter: (v) => nf.format(Number(v)) }),
31
36
  showLegend ? /* @__PURE__ */ jsx(Legend, {}) : null
32
37
  ] }) }) });
33
38
  }
34
39
 
35
40
  export { PieChart };
36
- //# sourceMappingURL=chunk-C5H44NSP.js.map
37
- //# sourceMappingURL=chunk-C5H44NSP.js.map
41
+ //# sourceMappingURL=chunk-WZRPGPLH.js.map
42
+ //# sourceMappingURL=chunk-WZRPGPLH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/widgets/charts/PieChart.tsx"],"names":["RechartsPieChart"],"mappings":";;;;;;AAiBO,SAAS,QAAA,CAAS;AAAA,EACvB,SAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA,GAAc,CAAA;AAAA,EACd,MAAA,GAAS;AACX,CAAA,EAAkB;AAChB,EAAA,MAAM,SAAS,cAAA,EAAe;AAC9B,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,MAAM,IAAI,IAAA,CAAK,aAAa,MAAM,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,QAAA,CAAS,CAAC,CAAA;AAClC,EAAA,MAAM,MAAA,GAAA,CAAU,OAAO,IAAA,IAAQ,IAAI,GAAA,CAAI,CAAC,OAAO,CAAA,MAAO;AAAA,IACpD,IAAA,EACE,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA,CAAE,4BAAA,EAA8B,eAAA,EAAiB,EAAE,MAAA,EAAQ,CAAA,GAAI,CAAA,EAAG,CAAA;AAAA,IAC3F;AAAA,GACF,CAAE,CAAA;AAEF,EAAA,2BACG,KAAA,EAAA,EAAI,aAAA,EAAa,MAAA,EAAQ,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAO,EACvD,8BAAC,mBAAA,EAAA,EAAoB,KAAA,EAAM,QAAO,MAAA,EAAO,MAAA,EACvC,+BAACA,UAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,MAAA;AAAA,QACN,OAAA,EAAQ,OAAA;AAAA,QACR,OAAA,EAAQ,MAAA;AAAA,QACR,WAAA;AAAA,QACA,WAAA,EAAY,KAAA;AAAA,QACZ,KAAA,EAAO,CAAC,KAAA,KAAU,EAAA,CAAG,OAAO,MAAA,CAAO,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,QAE9C,QAAA,EAAA,MAAA,CAAO,IAAI,CAAC,KAAA,EAAO,sBAClB,GAAA,CAAC,IAAA,EAAA,EAAsB,MAAM,QAAA,CAAS,KAAA,IAAS,EAAE,KAAA,EAAO,EAAA,EAAI,MAAM,EAAC,IAAK,CAAC,CAAA,EAAA,EAA9D,KAAA,CAAM,IAA2D,CAC7E;AAAA;AAAA,KACH;AAAA,oBACA,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAW,CAAC,CAAA,KAAM,GAAG,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,CAAA;AAAA,IAChD,UAAA,mBAAa,GAAA,CAAC,MAAA,EAAA,EAAO,CAAA,GAAK;AAAA,GAAA,EAC7B,GACF,CAAA,EACF,CAAA;AAEJ","file":"chunk-WZRPGPLH.js","sourcesContent":["import { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';\nimport { useMemo } from 'react';\nimport {\n Cell,\n Legend,\n Pie,\n PieChart as RechartsPieChart,\n ResponsiveContainer,\n Tooltip,\n} from 'recharts';\nimport { type ChartSubProps, colorFor } from '../types';\n\nexport interface PieChartProps extends ChartSubProps {\n innerRadius?: number | undefined;\n testId?: string | undefined;\n}\n\nexport function PieChart({\n chartData,\n height,\n showLegend,\n innerRadius = 0,\n testId = 'chart-pie',\n}: PieChartProps) {\n const locale = useArqelLocale();\n const t = useArqelTranslations();\n const nf = useMemo(() => new Intl.NumberFormat(locale), [locale]);\n const first = chartData.datasets[0];\n const slices = (first?.data ?? []).map((value, i) => ({\n name:\n chartData.labels[i] ?? t('arqel.chart.slice_fallback', 'Slice :number', { number: i + 1 }),\n value,\n }));\n\n return (\n <div data-testid={testId} style={{ width: '100%', height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsPieChart>\n <Pie\n data={slices}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={innerRadius}\n outerRadius=\"80%\"\n label={(entry) => nf.format(Number(entry.value))}\n >\n {slices.map((slice, i) => (\n <Cell key={slice.name} fill={colorFor(first ?? { label: '', data: [] }, i)} />\n ))}\n </Pie>\n <Tooltip formatter={(v) => nf.format(Number(v))} />\n {showLegend ? <Legend /> : null}\n </RechartsPieChart>\n </ResponsiveContainer>\n </div>\n );\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  import { PageHeader } from './chunk-MXUXMHOK.js';
2
2
  import { FormActions } from './chunk-MZMYV43C.js';
3
- import { FormRenderer } from './chunk-ZAM5TUPP.js';
3
+ import { FormRenderer } from './chunk-CMNZLA32.js';
4
4
  import { useArqelForm } from '@arqel-dev/hooks';
5
+ import { useArqelTranslations } from '@arqel-dev/react/utils';
5
6
  import { usePage, router } from '@inertiajs/react';
6
7
  import { jsxs, jsx } from 'react/jsx-runtime';
7
8
 
@@ -14,6 +15,7 @@ var FALLBACK_SCHEMA = {
14
15
  };
15
16
  function ArqelEditPage() {
16
17
  const page = usePage();
18
+ const t = useArqelTranslations();
17
19
  const props = page.props;
18
20
  const fields = props.fields ?? [];
19
21
  const record = props.record;
@@ -28,14 +30,10 @@ function ArqelEditPage() {
28
30
  preserveScroll: true
29
31
  });
30
32
  };
33
+ const label = props.resource?.label ?? t("arqel.pages.fallback", "record");
34
+ const editTitle = props.recordTitle ?? t("arqel.pages.edit", `Edit ${label}`, { label });
31
35
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
32
- /* @__PURE__ */ jsx(
33
- PageHeader,
34
- {
35
- title: props.recordTitle ?? `Edit ${props.resource?.label ?? "record"}`,
36
- description: props.recordSubtitle ?? null
37
- }
38
- ),
36
+ /* @__PURE__ */ jsx(PageHeader, { title: editTitle, description: props.recordSubtitle ?? null }),
39
37
  /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "space-y-6", children: [
40
38
  /* @__PURE__ */ jsx(
41
39
  FormRenderer,
@@ -53,5 +51,5 @@ function ArqelEditPage() {
53
51
  }
54
52
 
55
53
  export { ArqelEditPage };
56
- //# sourceMappingURL=chunk-UXN67E5L.js.map
57
- //# sourceMappingURL=chunk-UXN67E5L.js.map
54
+ //# sourceMappingURL=chunk-YQ6KXR3U.js.map
55
+ //# sourceMappingURL=chunk-YQ6KXR3U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pages/ArqelEditPage.tsx"],"names":[],"mappings":";;;;;;;;AAkBA,IAAM,eAAA,GAA8B;AAAA,EAClC,QAAQ,EAAC;AAAA,EACT,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO,IAAA;AAAA,EACP,MAAA,EAAQ,KAAA;AAAA,EACR,QAAA,EAAU;AACZ,CAAA;AASe,SAAR,aAAA,GAAuF;AAC5F,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,EAAA,MAAM,MAAA,GAAU,KAAA,CAAM,MAAA,IAAU,EAAC;AACjC,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,MAAM,MAAA,GAAU,MAA2C,IAAA,IAAQ,eAAA;AAEnE,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAuB;AACrC,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAM,EAAA,GAAK,MAAA,CAAQ,MAAA,EAAiD,EAAA,IAAM,EAAE,CAAA;AAC5E,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,QAAA,EAAU,IAAA,IAAQ,EAAA;AACrC,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,EAAU,SAAA,IAAa,QAAA;AAC9C,IAAA,MAAA,CAAO,GAAA,CAAI,GAAG,QAAQ,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,EAA+B;AAAA,MAC1E,cAAA,EAAgB;AAAA,KACjB,CAAA;AAAA,EACH,CAAA;AAKA,EAAA,MAAM,QAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,IAAS,CAAA,CAAE,wBAAwB,QAAQ,CAAA;AACzE,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,WAAA,IAAe,CAAA,CAAE,kBAAA,EAAoB,QAAQ,KAAK,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,CAAA;AAEvF,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAW,KAAA,EAAO,SAAA,EAAW,WAAA,EAAa,KAAA,CAAM,kBAAkB,IAAA,EAAM,CAAA;AAAA,oBACzE,IAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,MAAA,EAAQ,WAAU,WAAA,EAChC,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAQ,IAAA,CAAK,IAAA;AAAA,UACb,UAAU,CAAC,IAAA,EAAM,UAAU,IAAA,CAAK,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,UACnD,QAAQ,IAAA,CAAK;AAAA;AAAA,OACf;AAAA,sBACA,GAAA,CAAC,WAAA,EAAA,EAAY,UAAA,EAAY,IAAA,CAAK,UAAA,EAAY,UAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAK,EAAG;AAAA,KAAA,EACnF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-YQ6KXR3U.js","sourcesContent":["/**\n * Default Inertia page for `arqel::edit`.\n *\n * Same shape as `ArqelCreatePage` but seeds the form with the\n * server-emitted `record`. Submission posts to PUT `/{slug}/{id}`.\n */\n\nimport { useArqelForm } from '@arqel-dev/hooks';\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { FieldSchema } from '@arqel-dev/types/fields';\nimport type { FormSchema } from '@arqel-dev/types/forms';\nimport type { RecordType, ResourceEditProps } from '@arqel-dev/types/resources';\nimport { router, usePage } from '@inertiajs/react';\nimport type { FormEvent, JSX } from 'react';\nimport { FormActions } from '../form/FormActions.js';\nimport { FormRenderer } from '../form/FormRenderer.js';\nimport { PageHeader } from '../utility/PageHeader.js';\n\nconst FALLBACK_SCHEMA: FormSchema = {\n schema: [],\n columns: 1,\n model: null,\n inline: false,\n disabled: false,\n};\n\ninterface ArqelFormShape {\n data: Record<string, unknown>;\n setData: (name: string, value: unknown) => void;\n errors: Record<string, string[]>;\n processing: boolean;\n}\n\nexport default function ArqelEditPage<TRecord extends RecordType = RecordType>(): JSX.Element {\n const page = usePage();\n const t = useArqelTranslations();\n const props = page.props as unknown as ResourceEditProps<TRecord>;\n const fields = (props.fields ?? []) as FieldSchema[];\n const record = props.record;\n const schema = (props as unknown as { form?: FormSchema }).form ?? FALLBACK_SCHEMA;\n\n const form = useArqelForm({ fields, record }) as unknown as ArqelFormShape;\n\n const submit = (e: FormEvent): void => {\n e.preventDefault();\n const id = String((record as { id?: string | number } | undefined)?.id ?? '');\n const slug = props.resource?.slug ?? '';\n const basePath = props.resource?.panelPath ?? '/admin';\n router.put(`${basePath}/${slug}/${id}`, form.data as Record<string, never>, {\n preserveScroll: true,\n });\n };\n\n // Pre-interpolate the label into the English fallback so the title stays\n // correct even when the `arqel.pages.edit` key is absent from the shared\n // dictionary (the hook does not re-interpolate a raw fallback).\n const label = props.resource?.label ?? t('arqel.pages.fallback', 'record');\n const editTitle = props.recordTitle ?? t('arqel.pages.edit', `Edit ${label}`, { label });\n\n return (\n <div className=\"space-y-6\">\n <PageHeader title={editTitle} description={props.recordSubtitle ?? null} />\n <form onSubmit={submit} className=\"space-y-6\">\n <FormRenderer\n schema={schema}\n fields={fields}\n values={form.data}\n onChange={(name, value) => form.setData(name, value)}\n errors={form.errors}\n />\n <FormActions processing={form.processing} onCancel={() => window.history.back()} />\n </form>\n </div>\n );\n}\n"]}
@@ -1,17 +1,18 @@
1
- import { WidgetWrapper, StatCard } from './chunk-PSPJA5U6.js';
1
+ import { WidgetWrapper, StatCard } from './chunk-WMOBLT3Z.js';
2
2
  import { cn } from './chunk-B7ULUJVO.js';
3
- import { lazy, Suspense, useState, useRef, useEffect } from 'react';
3
+ import { useArqelTranslations, useArqelLocale } from '@arqel-dev/react/utils';
4
+ import { lazy, Suspense, useMemo, useState, useRef, useEffect } from 'react';
4
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
6
 
6
- var LineChart = lazy(() => import('./LineChart-GHMPHFZZ.js').then((m) => ({ default: m.LineChart })));
7
- var BarChart = lazy(() => import('./BarChart-KLHKTLO2.js').then((m) => ({ default: m.BarChart })));
8
- var AreaChart = lazy(() => import('./AreaChart-NMQ2RQGA.js').then((m) => ({ default: m.AreaChart })));
9
- var PieChart = lazy(() => import('./PieChart-T2VQOFPP.js').then((m) => ({ default: m.PieChart })));
7
+ var LineChart = lazy(() => import('./LineChart-RRPGAZON.js').then((m) => ({ default: m.LineChart })));
8
+ var BarChart = lazy(() => import('./BarChart-E52NJSJE.js').then((m) => ({ default: m.BarChart })));
9
+ var AreaChart = lazy(() => import('./AreaChart-JAZ6LUYG.js').then((m) => ({ default: m.AreaChart })));
10
+ var PieChart = lazy(() => import('./PieChart-SGN7V5LQ.js').then((m) => ({ default: m.PieChart })));
10
11
  var DonutChart = lazy(
11
- () => import('./DonutChart-L56R4QF2.js').then((m) => ({ default: m.DonutChart }))
12
+ () => import('./DonutChart-IGSF4LEB.js').then((m) => ({ default: m.DonutChart }))
12
13
  );
13
14
  var RadarChart = lazy(
14
- () => import('./RadarChart-CSWR5AO7.js').then((m) => ({ default: m.RadarChart }))
15
+ () => import('./RadarChart-3AOM736J.js').then((m) => ({ default: m.RadarChart }))
15
16
  );
16
17
  var REGISTRY = {
17
18
  line: LineChart,
@@ -22,6 +23,7 @@ var REGISTRY = {
22
23
  radar: RadarChart
23
24
  };
24
25
  function ChartCard({ widget }) {
26
+ const t = useArqelTranslations();
25
27
  const Chart = REGISTRY[widget.chartType] ?? LineChart;
26
28
  return /* @__PURE__ */ jsx(WidgetWrapper, { heading: widget.heading, description: widget.description, children: /* @__PURE__ */ jsx(
27
29
  Suspense,
@@ -30,7 +32,7 @@ function ChartCard({ widget }) {
30
32
  "div",
31
33
  {
32
34
  role: "status",
33
- "aria-label": "Loading chart",
35
+ "aria-label": t("arqel.aria.chart_loading", "Loading chart"),
34
36
  "data-testid": "chart-fallback",
35
37
  className: "animate-pulse rounded bg-muted",
36
38
  style: { height: widget.height }
@@ -100,6 +102,7 @@ function SelectControl({
100
102
  value,
101
103
  onChange
102
104
  }) {
105
+ const t = useArqelTranslations();
103
106
  const options = normaliseOptions(filter.options);
104
107
  const label = filter.label ?? filter.name;
105
108
  if (filter.multiple) {
@@ -132,7 +135,7 @@ function SelectControl({
132
135
  value: value === void 0 || value === null ? "" : String(value),
133
136
  onChange: (e) => onChange(e.target.value === "" ? null : e.target.value),
134
137
  children: [
135
- /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
138
+ /* @__PURE__ */ jsx("option", { value: "", children: t("table.filters.all", "All") }),
136
139
  options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
137
140
  ]
138
141
  }
@@ -144,17 +147,19 @@ function DateRangeControl({
144
147
  value,
145
148
  onChange
146
149
  }) {
150
+ const t = useArqelTranslations();
151
+ const label = filter.label ?? filter.name;
147
152
  const range = value && typeof value === "object" ? value : {};
148
153
  const fromValue = typeof range.from === "string" ? range.from : "";
149
154
  const toValue = typeof range.to === "string" ? range.to : "";
150
155
  return /* @__PURE__ */ jsxs("fieldset", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
151
- /* @__PURE__ */ jsx("legend", { children: filter.label ?? filter.name }),
156
+ /* @__PURE__ */ jsx("legend", { children: label }),
152
157
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
153
158
  /* @__PURE__ */ jsx(
154
159
  "input",
155
160
  {
156
161
  type: "date",
157
- "aria-label": `${filter.label ?? filter.name} from`,
162
+ "aria-label": t("table.filters.date_from", `${label} from`, { label }),
158
163
  className: controlClasses(),
159
164
  value: fromValue,
160
165
  onChange: (e) => onChange({ from: e.target.value || null, to: range.to ?? null })
@@ -165,7 +170,7 @@ function DateRangeControl({
165
170
  "input",
166
171
  {
167
172
  type: "date",
168
- "aria-label": `${filter.label ?? filter.name} to`,
173
+ "aria-label": t("table.filters.date_to", `${label} to`, { label }),
169
174
  className: controlClasses(),
170
175
  value: toValue,
171
176
  onChange: (e) => onChange({ from: range.from ?? null, to: e.target.value || null })
@@ -175,6 +180,9 @@ function DateRangeControl({
175
180
  ] });
176
181
  }
177
182
  function TableCard({ widget, className }) {
183
+ const t = useArqelTranslations();
184
+ const locale = useArqelLocale();
185
+ const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);
178
186
  return /* @__PURE__ */ jsx(
179
187
  WidgetWrapper,
180
188
  {
@@ -196,19 +204,25 @@ function TableCard({ widget, className }) {
196
204
  "tr",
197
205
  {
198
206
  className: "border-b border-border last:border-0",
199
- children: widget.columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5", children: formatCell(record[column.name]) }, column.name))
207
+ children: widget.columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5", children: formatCell(record[column.name], numberFormatter, t) }, column.name))
200
208
  },
201
209
  rowIndex
202
210
  )) })
203
211
  ] }) }),
204
- widget.seeAllUrl && /* @__PURE__ */ jsx("div", { className: "mt-3 text-right", children: /* @__PURE__ */ jsx("a", { href: widget.seeAllUrl, className: "text-sm text-primary", children: "See all \u2192" }) })
212
+ widget.seeAllUrl && /* @__PURE__ */ jsx("div", { className: "mt-3 text-right", children: /* @__PURE__ */ jsx("a", { href: widget.seeAllUrl, className: "text-sm text-primary", children: t("widgets.table.see_all", "See all \u2192") }) })
205
213
  ] })
206
214
  }
207
215
  );
208
216
  }
209
- function formatCell(value) {
217
+ function formatCell(value, numberFormatter, t) {
210
218
  if (value === null || value === void 0) return "";
211
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
219
+ if (typeof value === "number") {
220
+ return Number.isFinite(value) ? numberFormatter.format(value) : String(value);
221
+ }
222
+ if (typeof value === "boolean") {
223
+ return value ? t("table.boolean.true_label", "true") : t("table.boolean.false_label", "false");
224
+ }
225
+ if (typeof value === "string") {
212
226
  return String(value);
213
227
  }
214
228
  try {
@@ -218,6 +232,7 @@ function formatCell(value) {
218
232
  }
219
233
  }
220
234
  function WidgetRenderer({ widget, filterValues, fetcher }) {
235
+ const t = useArqelTranslations();
221
236
  const [data, setData] = useState(widget.data ?? null);
222
237
  const filterRef = useRef(filterValues);
223
238
  filterRef.current = filterValues;
@@ -260,11 +275,9 @@ function WidgetRenderer({ widget, filterValues, fetcher }) {
260
275
  case "table":
261
276
  return /* @__PURE__ */ jsx(TableCard, { widget: merged });
262
277
  default:
263
- return /* @__PURE__ */ jsxs("div", { role: "alert", className: "text-sm text-red-600", children: [
264
- "Widget type ",
265
- widget.type,
266
- " not registered"
267
- ] });
278
+ return /* @__PURE__ */ jsx("div", { role: "alert", className: "text-sm text-red-600", children: t("widgets.unknown_type", `Widget type ${widget.type} not registered`, {
279
+ type: widget.type
280
+ }) });
268
281
  }
269
282
  }
270
283
  function withFilters(baseUrl, filters) {
@@ -366,5 +379,5 @@ function normaliseFilters(raw) {
366
379
  }
367
380
 
368
381
  export { ChartCard, DashboardFilters, DashboardGrid, TableCard, WidgetRenderer };
369
- //# sourceMappingURL=chunk-HSDZM4AM.js.map
370
- //# sourceMappingURL=chunk-HSDZM4AM.js.map
382
+ //# sourceMappingURL=chunk-YYQ45W25.js.map
383
+ //# sourceMappingURL=chunk-YYQ45W25.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/widgets/ChartCard.tsx","../src/widgets/DashboardFilters.tsx","../src/widgets/TableCard.tsx","../src/widgets/WidgetRenderer.tsx","../src/widgets/DashboardGrid.tsx"],"names":["jsx","useArqelTranslations","jsxs","useState"],"mappings":"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","file":"chunk-YYQ45W25.js","sourcesContent":["import { useArqelTranslations } from '@arqel-dev/react/utils';\nimport { type ComponentType, lazy, Suspense } from 'react';\nimport type { ChartSubProps, ChartType, ChartWidgetProps } from './types';\nimport { WidgetWrapper } from './WidgetWrapper';\n\n/**\n * Lazy-loaded chart sub-components. Each `import()` becomes a separate chunk\n * in the build output so the ~60KB Recharts payload (and its sibling chart\n * primitives) stay out of the main `@arqel-dev/ui` bundle. Dashboards that only\n * use StatCard never pay for Recharts.\n */\nconst LineChart = lazy(() => import('./charts/LineChart').then((m) => ({ default: m.LineChart })));\nconst BarChart = lazy(() => import('./charts/BarChart').then((m) => ({ default: m.BarChart })));\nconst AreaChart = lazy(() => import('./charts/AreaChart').then((m) => ({ default: m.AreaChart })));\nconst PieChart = lazy(() => import('./charts/PieChart').then((m) => ({ default: m.PieChart })));\nconst DonutChart = lazy(() =>\n import('./charts/DonutChart').then((m) => ({ default: m.DonutChart })),\n);\nconst RadarChart = lazy(() =>\n import('./charts/RadarChart').then((m) => ({ default: m.RadarChart })),\n);\n\nconst REGISTRY: Record<ChartType, ComponentType<ChartSubProps>> = {\n line: LineChart,\n bar: BarChart,\n area: AreaChart,\n pie: PieChart,\n donut: DonutChart,\n radar: RadarChart,\n};\n\nexport function ChartCard({ widget }: ChartWidgetProps) {\n const t = useArqelTranslations();\n const Chart = REGISTRY[widget.chartType] ?? LineChart;\n\n return (\n <WidgetWrapper heading={widget.heading} description={widget.description}>\n <Suspense\n fallback={\n <div\n role=\"status\"\n aria-label={t('arqel.aria.chart_loading', 'Loading chart')}\n data-testid=\"chart-fallback\"\n className=\"animate-pulse rounded bg-muted\"\n style={{ height: widget.height }}\n />\n }\n >\n <Chart\n chartData={widget.chartData}\n chartOptions={widget.chartOptions}\n height={widget.height}\n showLegend={widget.showLegend}\n showGrid={widget.showGrid}\n />\n </Suspense>\n </WidgetWrapper>\n );\n}\n","/**\n * `<DashboardFilters>` — renders one control per dashboard `Filter`\n * payload (`Arqel\\Widgets\\Filters\\*`). Two filter types are wired in\n * Phase 2 part-3: `select` (single dropdown) and `date_range` (from/to\n * date inputs). Unknown types are dropped silently — extension points\n * land in later slices.\n *\n * Controlled component: callers own `values` and react to `onChange`.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport { cn } from '../utils/cn.js';\n\nexport interface SelectFilterPayload {\n name: string;\n type: 'select';\n label?: string | null;\n options?: Record<string, string> | Array<{ value: string; label: string }>;\n multiple?: boolean;\n}\n\nexport interface DateRangeFilterPayload {\n name: string;\n type: 'date_range';\n label?: string | null;\n}\n\nexport type DashboardFilterPayload =\n | SelectFilterPayload\n | DateRangeFilterPayload\n | { name: string; type: string; label?: string | null; [key: string]: unknown };\n\nexport interface DashboardFiltersProps {\n filters: DashboardFilterPayload[];\n values: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n className?: string | undefined;\n}\n\nexport function DashboardFilters({ filters, values, onChange, className }: DashboardFiltersProps) {\n if (!filters || filters.length === 0) return null;\n\n return (\n <div className={cn('flex flex-wrap gap-2', className)} data-testid=\"dashboard-filters\">\n {filters.map((filter) => (\n <FilterControl\n key={filter.name}\n filter={filter}\n value={values[filter.name]}\n onChange={(v) => onChange(filter.name, v)}\n />\n ))}\n </div>\n );\n}\n\nfunction FilterControl({\n filter,\n value,\n onChange,\n}: {\n filter: DashboardFilterPayload;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n if (filter.type === 'select') {\n return (\n <SelectControl filter={filter as SelectFilterPayload} value={value} onChange={onChange} />\n );\n }\n if (filter.type === 'date_range') {\n return (\n <DateRangeControl\n filter={filter as DateRangeFilterPayload}\n value={value}\n onChange={onChange}\n />\n );\n }\n return null;\n}\n\nfunction controlClasses() {\n return cn(\n 'h-9 rounded-sm border border-[var(--input)]',\n 'bg-background px-2 text-sm',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n );\n}\n\nfunction normaliseOptions(\n raw: SelectFilterPayload['options'],\n): Array<{ value: string; label: string }> {\n if (!raw) return [];\n if (Array.isArray(raw)) {\n return raw.map((o) => ({ value: String(o.value), label: String(o.label ?? o.value) }));\n }\n return Object.entries(raw).map(([k, v]) => ({ value: String(k), label: String(v) }));\n}\n\nfunction SelectControl({\n filter,\n value,\n onChange,\n}: {\n filter: SelectFilterPayload;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n const options = normaliseOptions(filter.options);\n const label = filter.label ?? filter.name;\n\n if (filter.multiple) {\n const selected = Array.isArray(value) ? (value as Array<string | number>).map(String) : [];\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {label}\n <select\n multiple\n aria-label={label}\n className={cn(controlClasses(), 'h-auto min-h-[2.25rem] py-1')}\n value={selected}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next.length === 0 ? null : next);\n }}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {label}\n <select\n aria-label={label}\n className={controlClasses()}\n value={value === undefined || value === null ? '' : String(value)}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n >\n <option value=\"\">{t('table.filters.all', 'All')}</option>\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction DateRangeControl({\n filter,\n value,\n onChange,\n}: {\n filter: DateRangeFilterPayload;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n const label = filter.label ?? filter.name;\n const range = (value && typeof value === 'object' ? (value as Record<string, unknown>) : {}) as {\n from?: unknown;\n to?: unknown;\n };\n const fromValue = typeof range.from === 'string' ? range.from : '';\n const toValue = typeof range.to === 'string' ? range.to : '';\n\n return (\n <fieldset className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n <legend>{label}</legend>\n <div className=\"flex items-center gap-1\">\n <input\n type=\"date\"\n aria-label={t('table.filters.date_from', `${label} from`, { label })}\n className={controlClasses()}\n value={fromValue}\n onChange={(e) => onChange({ from: e.target.value || null, to: range.to ?? null })}\n />\n <span aria-hidden=\"true\">–</span>\n <input\n type=\"date\"\n aria-label={t('table.filters.date_to', `${label} to`, { label })}\n className={controlClasses()}\n value={toValue}\n onChange={(e) => onChange({ from: range.from ?? null, to: e.target.value || null })}\n />\n </div>\n </fieldset>\n );\n}\n","/**\n * `<TableCard>` — minimal mini-table widget rendered inside a dashboard.\n *\n * Mirrors the payload produced by `Arqel\\Widgets\\TableWidget::data()`:\n * `{ columns, records, limit, seeAllUrl, loadError? }`. The component is\n * intentionally schema-light — each column carries `name` + `label` and\n * cells extract `record[column.name]` verbatim. Renders a `role=\"alert\"`\n * panel when the PHP side surfaced a `loadError` instead of trying to\n * draw an empty table.\n */\n\nimport { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';\nimport { useMemo } from 'react';\nimport { cn } from '../utils/cn.js';\nimport { WidgetWrapper } from './WidgetWrapper.js';\n\nexport interface TableCardColumn {\n name: string;\n label?: string | null;\n}\n\nexport interface TableCardRecord {\n [key: string]: unknown;\n}\n\nexport interface TableCardWidget {\n name: string;\n type: 'table';\n heading?: string | null;\n description?: string | null;\n columns: TableCardColumn[];\n records: TableCardRecord[];\n limit: number;\n seeAllUrl?: string | null;\n loadError?: string | null;\n}\n\nexport interface TableCardProps {\n widget: TableCardWidget;\n className?: string | undefined;\n}\n\nexport function TableCard({ widget, className }: TableCardProps) {\n const t = useArqelTranslations();\n const locale = useArqelLocale();\n const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);\n return (\n <WidgetWrapper\n heading={widget.heading ?? undefined}\n description={widget.description ?? undefined}\n className={className}\n >\n {widget.loadError ? (\n <div role=\"alert\" className=\"text-sm text-red-600\">\n {widget.loadError}\n </div>\n ) : (\n <>\n <div className=\"overflow-x-auto\">\n <table className={cn('w-full border-collapse text-sm', 'text-foreground')}>\n <thead>\n <tr className=\"border-b border-border text-left\">\n {widget.columns.map((column) => (\n <th\n key={column.name}\n scope=\"col\"\n className=\"px-2 py-1.5 font-medium text-muted-foreground\"\n >\n {column.label ?? column.name}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {widget.records.map((record, rowIndex) => (\n <tr\n // biome-ignore lint/suspicious/noArrayIndexKey: records may lack a stable id\n key={rowIndex}\n className=\"border-b border-border last:border-0\"\n >\n {widget.columns.map((column) => (\n <td key={column.name} className=\"px-2 py-1.5\">\n {formatCell(record[column.name], numberFormatter, t)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {widget.seeAllUrl && (\n <div className=\"mt-3 text-right\">\n <a href={widget.seeAllUrl} className=\"text-sm text-primary\">\n {t('widgets.table.see_all', 'See all →')}\n </a>\n </div>\n )}\n </>\n )}\n </WidgetWrapper>\n );\n}\n\nfunction formatCell(\n value: unknown,\n numberFormatter: Intl.NumberFormat,\n t: (key: string, fallback?: string) => string,\n): string {\n if (value === null || value === undefined) return '';\n // Numbers are grouped/decimal-formatted for the active locale so a cell of\n // `1500000` reads `1.500.000` under pt-BR instead of the raw en-US digits.\n if (typeof value === 'number') {\n return Number.isFinite(value) ? numberFormatter.format(value) : String(value);\n }\n // Booleans render a localized truth label (mirroring cells.tsx) so a pt-BR\n // viewer sees the localized value instead of the literal 'true'/'false'.\n if (typeof value === 'boolean') {\n return value ? t('table.boolean.true_label', 'true') : t('table.boolean.false_label', 'false');\n }\n if (typeof value === 'string') {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '';\n }\n}\n","/**\n * `<WidgetRenderer>` — dispatches widget payloads to the right card\n * by `widget.type` (`stat`, `chart`, `table`). Unknown / `custom` types\n * surface a `role=\"alert\"` so a misconfigured registry never silently\n * blanks the dashboard.\n *\n * Two server interactions live here:\n * 1. **Polling** — when `widget.poll > 0`, re-fetch the widget data\n * endpoint every N seconds and replace the inline payload.\n * 2. **Deferred** — when `widget.deferred === true` and `data` is\n * `null`, fetch once on mount.\n *\n * Both call the canonical endpoint\n * `/admin/dashboards/{dashboardId}/widgets/{widgetId}/data`. The\n * controller wraps the payload under `{ data: ... }`, so `doFetch`\n * unwraps that envelope before storing — the resulting shape matches\n * the SSR / Inertia path, which already seeds from `widget.data`. The\n * active `DashboardFilters` selection is forwarded as `filters[k]=v`\n * query params so deferred / poll refetches stay segmented.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport { useEffect, useRef, useState } from 'react';\nimport { ChartCard } from './ChartCard.js';\nimport { StatCard } from './StatCard.js';\nimport { TableCard } from './TableCard.js';\n\nexport interface WidgetPayload {\n id?: string;\n name: string;\n type: string;\n component?: string;\n data?: unknown;\n poll?: number | null;\n deferred?: boolean;\n dashboardId?: string;\n widgetId?: string;\n [key: string]: unknown;\n}\n\nexport interface WidgetRendererProps {\n widget: WidgetPayload;\n filterValues?: Record<string, unknown>;\n fetcher?: ((url: string) => Promise<unknown>) | undefined;\n}\n\nexport function WidgetRenderer({ widget, filterValues, fetcher }: WidgetRendererProps) {\n const t = useArqelTranslations();\n const [data, setData] = useState<unknown>(widget.data ?? null);\n const filterRef = useRef(filterValues);\n filterRef.current = filterValues;\n\n const dashboardId = widget.dashboardId;\n // `Dashboard::findWidget` matches on `id()` (`<type>:<name>`), so the refetch\n // must target that — `Dashboard::resolve` now injects `widgetId`. Fall back to\n // the serialized `id` (also the full `id()`) before the bare `name`.\n const widgetId = widget.widgetId ?? widget.id ?? widget.name;\n const poll = typeof widget.poll === 'number' ? widget.poll : 0;\n const deferred = widget.deferred === true;\n // Capture the initial-payload presence in a ref so the effect doesn't\n // need to take `widget.data` as a dep (we only consult it once on mount).\n const hasInlineDataRef = useRef(widget.data !== null && widget.data !== undefined);\n\n useEffect(() => {\n if (!dashboardId || !widgetId) return undefined;\n\n const baseUrl = `/admin/dashboards/${dashboardId}/widgets/${widgetId}/data`;\n const doFetch = async () => {\n try {\n // Build the URL with the *live* filters so deferred / poll refetches\n // honour the dashboard's `DashboardFilters` selection. The server\n // reads `$request->input('filters')` as an array, so each entry is\n // serialised as `filters[key]=value`.\n const url = withFilters(baseUrl, filterRef.current);\n const body = fetcher\n ? await fetcher(url)\n : await fetch(url, { headers: { Accept: 'application/json' } }).then((r) => r.json());\n // Unwrap the controller envelope (`{ data: ... }`) so the fetch\n // payload shape matches the SSR / Inertia path, which already seeds\n // from the unwrapped `widget.data`. Defensive: accept bare payloads.\n const result =\n body && typeof body === 'object' && 'data' in (body as Record<string, unknown>)\n ? (body as Record<string, unknown>)['data']\n : body;\n setData(result);\n } catch {\n // Swallow — the inline payload (or the previous successful poll) stays.\n }\n };\n\n let interval: ReturnType<typeof setInterval> | undefined;\n\n if (deferred && !hasInlineDataRef.current) {\n void doFetch();\n }\n\n if (poll > 0) {\n interval = setInterval(() => {\n void doFetch();\n }, poll * 1000);\n }\n\n return () => {\n if (interval) clearInterval(interval);\n };\n }, [dashboardId, widgetId, poll, deferred, fetcher]);\n\n const merged = mergeData(widget, data);\n\n switch (widget.type) {\n case 'stat':\n return <StatCard widget={merged as never} />;\n case 'chart':\n return <ChartCard widget={merged as never} />;\n case 'table':\n return <TableCard widget={merged as never} />;\n default:\n return (\n <div role=\"alert\" className=\"text-sm text-red-600\">\n {t('widgets.unknown_type', `Widget type ${widget.type} not registered`, {\n type: widget.type,\n })}\n </div>\n );\n }\n}\n\n/**\n * Append non-empty filter values as query params so the Laravel controller\n * resolves them via `$request->input('filters')` as a nested array. The shape\n * must mirror what the SSR / deep-link path produces (`router.get(path,\n * { filters })`, qs bracket notation) so a deferred / polling widget's lazy\n * refetch agrees with its SSR payload:\n * - **array** → `filters[key][]=el` per element (multi-`SelectControl`, #189)\n * - **plain object** → `filters[key][subKey]=val` per leaf (`DateRangeControl`\n * emits `{from,to}` → `filters[range][from]=..&filters[range][to]=..`)\n * - **scalar** → `filters[key]=value`\n * `null` / `undefined` / empty-string values (and leaves) are skipped to keep\n * the URL clean and match the prior scalar behaviour.\n */\nfunction withFilters(baseUrl: string, filters: Record<string, unknown> | undefined): string {\n if (!filters) return baseUrl;\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(filters)) {\n appendFilterValue(params, `filters[${key}]`, value);\n }\n\n const query = params.toString();\n return query ? `${baseUrl}?${query}` : baseUrl;\n}\n\n/**\n * Serialize a single filter value under `prefix`, recursing one level for the\n * array / plain-object shapes the dashboard filters emit (scalar | string[] |\n * `{from,to}`). `Array.isArray` is checked before the plain-object branch since\n * arrays are also objects. Empty leaves are skipped, never appended.\n */\nfunction appendFilterValue(params: URLSearchParams, prefix: string, value: unknown): void {\n if (value === null || value === undefined || value === '') return;\n\n if (Array.isArray(value)) {\n for (const el of value) {\n appendFilterValue(params, `${prefix}[]`, el);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [subKey, subVal] of Object.entries(value as Record<string, unknown>)) {\n appendFilterValue(params, `${prefix}[${subKey}]`, subVal);\n }\n return;\n }\n\n params.append(prefix, String(value));\n}\n\nfunction mergeData(widget: WidgetPayload, data: unknown): Record<string, unknown> {\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n return { ...widget, ...(data as Record<string, unknown>) };\n }\n return { ...widget, data };\n}\n","/**\n * `<DashboardGrid>` — top-level layout for an Arqel dashboard.\n *\n * Renders the dashboard heading + description, the filter bar (when the\n * dashboard declares filters), and a CSS Grid of widgets. Column count\n * accepts either a flat int or a responsive map (`{sm,md,lg,xl,2xl}`)\n * matching `Arqel\\Widgets\\Dashboard::columns()`. Each widget honours\n * `columnSpan` (defaults to 1) via `gridColumn: span N`.\n *\n * Filter values are controlled internally when `onFilterChange` is not\n * provided; supply that prop (and `filterValues`) to lift state out\n * (e.g., to push it to the URL through Inertia).\n */\n\nimport { type CSSProperties, useState } from 'react';\nimport { cn } from '../utils/cn.js';\nimport { type DashboardFilterPayload, DashboardFilters } from './DashboardFilters.js';\nimport { type WidgetPayload, WidgetRenderer } from './WidgetRenderer.js';\n\nexport interface DashboardPayload {\n id: string;\n label: string;\n path?: string | null;\n heading?: string | null;\n description?: string | null;\n widgets: WidgetPayload[];\n filters?: DashboardFilterPayload[] | Record<string, unknown> | null;\n columns: number | Partial<Record<'sm' | 'md' | 'lg' | 'xl' | '2xl', number>>;\n}\n\nexport interface DashboardGridProps {\n dashboard: DashboardPayload;\n filterValues?: Record<string, unknown>;\n onFilterChange?: ((name: string, value: unknown) => void) | undefined;\n className?: string | undefined;\n}\n\nconst BREAKPOINT_PREFIX: Record<string, string> = {\n sm: 'sm:',\n md: 'md:',\n lg: 'lg:',\n xl: 'xl:',\n '2xl': '2xl:',\n};\n\nexport function DashboardGrid({\n dashboard,\n filterValues,\n onFilterChange,\n className,\n}: DashboardGridProps) {\n const [internalValues, setInternalValues] = useState<Record<string, unknown>>(filterValues ?? {});\n const values = filterValues ?? internalValues;\n\n const handleChange = (name: string, value: unknown) => {\n if (onFilterChange) {\n onFilterChange(name, value);\n } else {\n setInternalValues((prev) => ({ ...prev, [name]: value }));\n }\n };\n\n const filterPayload = normaliseFilters(dashboard.filters);\n const heading = dashboard.heading ?? dashboard.label;\n\n return (\n <div className={cn('space-y-4', className)}>\n <header className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-1\">\n {heading && <h1 className=\"text-xl font-semibold\">{heading}</h1>}\n {dashboard.description && (\n <p className=\"text-sm text-muted-foreground\">{dashboard.description}</p>\n )}\n </div>\n {filterPayload.length > 0 && (\n <DashboardFilters filters={filterPayload} values={values} onChange={handleChange} />\n )}\n </header>\n\n <div\n className={cn('grid gap-4', gridColsClass(dashboard.columns))}\n data-testid=\"dashboard-grid\"\n >\n {dashboard.widgets.map((widget) => {\n const rawSpan = (widget as { columnSpan?: unknown }).columnSpan;\n const span = typeof rawSpan === 'number' ? rawSpan : 1;\n const style: CSSProperties = { gridColumn: `span ${span}` };\n return (\n <div key={widget.name} style={style} data-widget-slot={widget.name}>\n <WidgetRenderer widget={widget} filterValues={values} />\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction gridColsClass(columns: DashboardPayload['columns']): string {\n if (typeof columns === 'number') {\n return `grid-cols-${Math.max(1, Math.min(12, columns))}`;\n }\n const parts: string[] = [];\n // Base fallback when no `sm` provided.\n parts.push('grid-cols-1');\n for (const bp of ['sm', 'md', 'lg', 'xl', '2xl'] as const) {\n const value = columns[bp];\n if (typeof value === 'number') {\n parts.push(`${BREAKPOINT_PREFIX[bp]}grid-cols-${Math.max(1, Math.min(12, value))}`);\n }\n }\n return parts.join(' ');\n}\n\nfunction normaliseFilters(raw: DashboardPayload['filters']): DashboardFilterPayload[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw;\n // Legacy `Record<string, mixed>` passthrough — render as a select-less\n // empty list so we don't crash. The declarative path is preferred.\n return [];\n}\n"]}
package/dist/flash.js CHANGED
@@ -1,4 +1,4 @@
1
- export { FlashContainer, FlashToast } from './chunk-DSULVRB6.js';
1
+ export { FlashContainer, FlashToast } from './chunk-GJ2FKAOM.js';
2
2
  import './chunk-B7ULUJVO.js';
3
3
  //# sourceMappingURL=flash.js.map
4
4
  //# sourceMappingURL=flash.js.map
package/dist/form.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { F as FieldComponent, a as FieldRenderer, b as FieldRendererProps, c as FormActions, d as FormActionsProps, e as FormRenderer, f as FormRendererProps, g as clearFieldRegistry, h as getFieldComponent, i as getRegisteredFields, r as registerField, u as unregisterField } from './FormRenderer-BJBRIkfH.js';
1
+ export { F as FieldComponent, a as FieldRenderer, b as FieldRendererProps, c as FormActions, d as FormActionsProps, e as FormRenderer, f as FormRendererProps, g as clearFieldRegistry, h as getFieldComponent, i as getRegisteredFields, r as registerField, u as unregisterField } from './FormRenderer-By8fZp4t.js';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { FieldsetProps, GridProps, SectionProps, TabsProps } from '@arqel-dev/types/forms';
4
4
  import { ReactNode, ReactElement } from 'react';
@@ -55,6 +55,8 @@ interface NativeProps {
55
55
  className?: string | undefined;
56
56
  inputId?: string | undefined;
57
57
  describedBy?: string | undefined;
58
+ /** When true, the control is in an error state — sets `aria-invalid`. */
59
+ invalid?: boolean | undefined;
58
60
  }
59
61
  declare function NativeFieldInput(props: NativeProps): react_jsx_runtime.JSX.Element;
60
62
 
package/dist/form.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { FormActions } from './chunk-MZMYV43C.js';
2
- export { FieldRenderer, FormFieldset, FormGrid, FormRenderer, FormSection, FormTabs, NativeFieldInput, clearFieldRegistry, getFieldComponent, getRegisteredFields, registerField, unregisterField } from './chunk-ZAM5TUPP.js';
2
+ export { FieldRenderer, FormFieldset, FormGrid, FormRenderer, FormSection, FormTabs, NativeFieldInput, clearFieldRegistry, getFieldComponent, getRegisteredFields, registerField, unregisterField } from './chunk-CMNZLA32.js';
3
3
  import './chunk-H23VX3RR.js';
4
4
  import './chunk-B7ULUJVO.js';
5
5
  //# sourceMappingURL=form.js.map
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { ActionButton, ActionButtonProps, ActionFormModal, ActionFormModalProps, ActionMenu, ActionMenuProps, Button, ButtonProps, ConfirmDialog, ConfirmDialogProps, buttonVariants } from './action.js';
2
2
  export { CanAccess, CanAccessProps } from './auth.js';
3
3
  export { FlashContainer, FlashContainerProps, FlashKind, FlashPosition, FlashToast, FlashToastProps } from './flash.js';
4
- export { F as FieldComponent, a as FieldRenderer, b as FieldRendererProps, c as FormActions, d as FormActionsProps, e as FormRenderer, f as FormRendererProps, g as clearFieldRegistry, h as getFieldComponent, r as registerField } from './FormRenderer-BJBRIkfH.js';
4
+ export { F as FieldComponent, a as FieldRenderer, b as FieldRendererProps, c as FormActions, d as FormActionsProps, e as FormRenderer, f as FormRendererProps, g as clearFieldRegistry, h as getFieldComponent, r as registerField } from './FormRenderer-By8fZp4t.js';
5
5
  export { CommandPalette, CommandPaletteProps, PaletteCommand } from './palette.js';
6
6
  export { Alert, AlertDescription, AlertTitle, Badge, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Input, Label, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Skeleton, Textarea, badgeVariants } from './primitives.js';
7
7
  export { ResourceIndex, ResourceIndexUIProps } from './resource.js';
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
- export { Breadcrumbs, EmptyState, ErrorState, LoadingSkeleton } from './chunk-MTNFFSVA.js';
2
- export { StatCard, WidgetWrapper } from './chunk-PSPJA5U6.js';
1
+ export { Breadcrumbs, EmptyState, ErrorState, LoadingSkeleton } from './chunk-SK6H7ARE.js';
2
+ export { StatCard, WidgetWrapper } from './chunk-WMOBLT3Z.js';
3
3
  export { Alert, AlertDescription, AlertTitle, Badge, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Label, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Textarea, badgeVariants } from './chunk-K7QY56XN.js';
4
4
  export { PageHeader } from './chunk-MXUXMHOK.js';
5
- export { AppShell, Footer, MainContent, Sidebar, Topbar } from './chunk-N5U2BB6T.js';
6
- export { CommandPalette } from './chunk-FV7RESKL.js';
5
+ export { AppShell, Footer, MainContent, Sidebar, Topbar } from './chunk-4VWNBMMA.js';
6
+ export { CommandPalette } from './chunk-HNUUZEOL.js';
7
7
  export { Input, Separator, Skeleton } from './chunk-R4BOUU6Y.js';
8
- export { ResourceIndex } from './chunk-CVAMCRLL.js';
9
- export { DataTable, TableFilters, TablePagination, TableToolbar } from './chunk-AZICSFBA.js';
8
+ export { ResourceIndex } from './chunk-EG2DASKR.js';
9
+ export { DataTable, TableFilters, TablePagination, TableToolbar } from './chunk-S5UNPCMQ.js';
10
10
  import './chunk-RMPOR2YZ.js';
11
- export { ActionButton, ActionFormModal, ActionMenu, ConfirmDialog } from './chunk-FP5R6WED.js';
11
+ export { ActionButton, ActionFormModal, ActionMenu, ConfirmDialog } from './chunk-2JUWLJ3K.js';
12
12
  import './chunk-3HN4ARGG.js';
13
13
  export { FormActions } from './chunk-MZMYV43C.js';
14
- export { FieldRenderer, FormRenderer, clearFieldRegistry, getFieldComponent, registerField } from './chunk-ZAM5TUPP.js';
14
+ export { FieldRenderer, FormRenderer, clearFieldRegistry, getFieldComponent, registerField } from './chunk-CMNZLA32.js';
15
15
  export { Button, buttonVariants } from './chunk-H23VX3RR.js';
16
16
  export { CanAccess } from './chunk-RNAMHQM6.js';
17
- export { FlashContainer, FlashToast } from './chunk-DSULVRB6.js';
17
+ export { FlashContainer, FlashToast } from './chunk-GJ2FKAOM.js';
18
18
  export { cn } from './chunk-B7ULUJVO.js';
19
19
  //# sourceMappingURL=index.js.map
20
20
  //# sourceMappingURL=index.js.map
package/dist/pages.js CHANGED
@@ -1,28 +1,28 @@
1
- export { ArqelShowPage } from './chunk-N6WLCHQE.js';
2
- export { ArqelDashboardPage } from './chunk-BJER6TOI.js';
3
- export { ArqelEditPage } from './chunk-UXN67E5L.js';
4
- export { ArqelIndexPage } from './chunk-4I5S6MH3.js';
5
- import './chunk-HSDZM4AM.js';
6
- export { ArqelCreatePage } from './chunk-37FLEB4N.js';
7
- import './chunk-PSPJA5U6.js';
1
+ export { ArqelShowPage } from './chunk-Q7WGPKUN.js';
2
+ export { ArqelDashboardPage } from './chunk-3VSDQCFO.js';
3
+ export { ArqelEditPage } from './chunk-YQ6KXR3U.js';
4
+ export { ArqelIndexPage } from './chunk-LLANMODS.js';
5
+ import './chunk-YYQ45W25.js';
6
+ export { ArqelCreatePage } from './chunk-IO6RMVUF.js';
7
+ import './chunk-WMOBLT3Z.js';
8
8
  import './chunk-MXUXMHOK.js';
9
- import './chunk-CVAMCRLL.js';
10
- import './chunk-AZICSFBA.js';
9
+ import './chunk-EG2DASKR.js';
10
+ import './chunk-S5UNPCMQ.js';
11
11
  import './chunk-RMPOR2YZ.js';
12
- import './chunk-FP5R6WED.js';
12
+ import './chunk-2JUWLJ3K.js';
13
13
  import './chunk-3HN4ARGG.js';
14
14
  import './chunk-MZMYV43C.js';
15
- import './chunk-ZAM5TUPP.js';
15
+ import './chunk-CMNZLA32.js';
16
16
  import './chunk-H23VX3RR.js';
17
17
  import './chunk-B7ULUJVO.js';
18
18
 
19
19
  // src/pages/index.ts
20
20
  var arqelPages = {
21
- "arqel::index": () => import('./ArqelIndexPage-R6JL5KOH.js'),
22
- "arqel::create": () => import('./ArqelCreatePage-MV4JN2MO.js'),
23
- "arqel::edit": () => import('./ArqelEditPage-7J3IS2BR.js'),
24
- "arqel::show": () => import('./ArqelShowPage-5WWUSYC7.js'),
25
- "arqel::dashboard": () => import('./ArqelDashboardPage-QK3BYVK3.js')
21
+ "arqel::index": () => import('./ArqelIndexPage-RGZWKKAX.js'),
22
+ "arqel::create": () => import('./ArqelCreatePage-UZAHV4DK.js'),
23
+ "arqel::edit": () => import('./ArqelEditPage-RRYFYOTC.js'),
24
+ "arqel::show": () => import('./ArqelShowPage-TVCJAV2F.js'),
25
+ "arqel::dashboard": () => import('./ArqelDashboardPage-Z5R4XSH4.js')
26
26
  };
27
27
 
28
28
  export { arqelPages };
package/dist/palette.js CHANGED
@@ -1,3 +1,3 @@
1
- export { CommandPalette } from './chunk-FV7RESKL.js';
1
+ export { CommandPalette } from './chunk-HNUUZEOL.js';
2
2
  //# sourceMappingURL=palette.js.map
3
3
  //# sourceMappingURL=palette.js.map
package/dist/resource.js CHANGED
@@ -1,5 +1,5 @@
1
- export { ResourceIndex } from './chunk-CVAMCRLL.js';
2
- import './chunk-AZICSFBA.js';
1
+ export { ResourceIndex } from './chunk-EG2DASKR.js';
2
+ import './chunk-S5UNPCMQ.js';
3
3
  import './chunk-RMPOR2YZ.js';
4
4
  import './chunk-H23VX3RR.js';
5
5
  import './chunk-B7ULUJVO.js';
package/dist/shell.js CHANGED
@@ -1,10 +1,11 @@
1
- export { AppShell, Footer, MainContent, Sidebar, Topbar } from './chunk-N5U2BB6T.js';
2
- import './chunk-FV7RESKL.js';
1
+ export { AppShell, Footer, MainContent, Sidebar, Topbar } from './chunk-4VWNBMMA.js';
2
+ import './chunk-HNUUZEOL.js';
3
3
  import './chunk-R4BOUU6Y.js';
4
4
  import './chunk-RMPOR2YZ.js';
5
5
  import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-3HN4ARGG.js';
6
6
  import { Button } from './chunk-H23VX3RR.js';
7
7
  import './chunk-B7ULUJVO.js';
8
+ import { useArqelTranslations } from '@arqel-dev/react/utils';
8
9
  import { router } from '@inertiajs/react';
9
10
  import { jsxs, jsx } from 'react/jsx-runtime';
10
11
 
@@ -14,9 +15,10 @@ function TenantSwitcher({
14
15
  available,
15
16
  switchUrl
16
17
  }) {
18
+ const t = useArqelTranslations();
17
19
  if (!current || available.length <= 1) return null;
18
20
  const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;
19
- const labelFor = (tenant) => tenant.name?.trim() ? tenant.name : `Tenant ${tenant.id}`;
21
+ const labelFor = (tenant) => tenant.name?.trim() ? tenant.name : t("arqel.tenant.unnamed", `Tenant ${tenant.id}`, { id: tenant.id });
20
22
  const currentLabel = labelFor(current);
21
23
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
22
24
  /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -25,7 +27,9 @@ function TenantSwitcher({
25
27
  variant: "ghost",
26
28
  size: "sm",
27
29
  "data-testid": "tenant-switcher-trigger",
28
- "aria-label": `Switch tenant (current: ${currentLabel})`,
30
+ "aria-label": t("arqel.aria.tenant_switch", `Switch tenant (current: ${currentLabel})`, {
31
+ tenant: currentLabel
32
+ }),
29
33
  children: currentLabel
30
34
  }
31
35
  ) }),
package/dist/shell.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/TenantSwitcher.tsx"],"names":[],"mappings":";;;;;;;;;;AAiCA,IAAM,kBAAA,GAAqB,CAAC,EAAA,KAAgC,CAAA,eAAA,EAAkB,EAAE,CAAA,OAAA,CAAA;AAEzE,SAAS,cAAA,CAAe;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAC1C,EAAA,IAAI,CAAC,OAAA,IAAW,SAAA,CAAU,MAAA,IAAU,GAAG,OAAO,IAAA;AAE9C,EAAA,MAAM,WAAW,SAAA,IAAa,kBAAA;AAC9B,EAAA,MAAM,QAAA,GAAW,CAAC,MAAA,KAChB,MAAA,CAAO,IAAA,EAAM,IAAA,EAAK,GAAI,MAAA,CAAO,IAAA,GAAO,CAAA,OAAA,EAAU,MAAA,CAAO,EAAE,CAAA,CAAA;AACzD,EAAA,MAAM,YAAA,GAAe,SAAS,OAAO,CAAA;AAErC,EAAA,4BACG,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,SAAO,IAAA,EAC1B,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,OAAA;AAAA,QACR,IAAA,EAAK,IAAA;AAAA,QACL,aAAA,EAAY,yBAAA;AAAA,QACZ,YAAA,EAAY,2BAA2B,YAAY,CAAA,CAAA,CAAA;AAAA,QAElD,QAAA,EAAA;AAAA;AAAA,KACH,EACF,CAAA;AAAA,wBACC,mBAAA,EAAA,EAAoB,KAAA,EAAM,OACxB,QAAA,EAAA,SAAA,CAAU,GAAA,CAAI,CAAC,MAAA,KAAW;AACzB,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,EAAA,KAAO,OAAA,CAAQ,EAAA;AACxC,MAAA,uBACE,IAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UAEC,aAAA,EAAa,CAAA,uBAAA,EAA0B,MAAA,CAAO,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAAA,UACxD,QAAA,EAAU,SAAA;AAAA,UACV,UAAU,MAAM;AACd,YAAA,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG,EAAC,EAAG,EAAE,cAAA,EAAgB,IAAA,EAAM,CAAA;AAAA,UAC/D,CAAA;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,QAAA,CAAS,MAAM,CAAA;AAAA,YACf,YAAY,SAAA,GAAO;AAAA;AAAA,SAAA;AAAA,QARf,MAAA,CAAO,OAAO,EAAE;AAAA,OASvB;AAAA,IAEJ,CAAC,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ","file":"shell.js","sourcesContent":["/**\n * `<TenantSwitcher>` — dropdown that lists tenants the user can\n * access and dispatches `POST /admin/tenants/{id}/switch` via\n * Inertia router. Renders nothing when there is no current tenant\n * or the user only has access to one tenant.\n *\n * Mounts in the `tenantSwitcher` slot of `<Topbar>`. The current\n * tenant is read from `props.tenant.current` shared by the\n * server-side `HandleArqelInertiaRequests`; available tenants\n * come from the same payload.\n */\n\nimport type { TenantSummary } from '@arqel-dev/types/tenant';\nimport { router } from '@inertiajs/react';\nimport type { JSX } from 'react';\nimport { Button } from '../action/Button.js';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../shadcn/ui/dropdown-menu.js';\n\nexport interface TenantSwitcherProps {\n current: TenantSummary | null;\n available: ReadonlyArray<TenantSummary>;\n /**\n * Path template for switching; defaults to\n * `/admin/tenants/{id}/switch`.\n */\n switchUrl?: (tenantId: string | number) => string;\n}\n\nconst DEFAULT_SWITCH_URL = (id: string | number): string => `/admin/tenants/${id}/switch`;\n\nexport function TenantSwitcher({\n current,\n available,\n switchUrl,\n}: TenantSwitcherProps): JSX.Element | null {\n if (!current || available.length <= 1) return null;\n\n const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;\n const labelFor = (tenant: TenantSummary): string =>\n tenant.name?.trim() ? tenant.name : `Tenant ${tenant.id}`;\n const currentLabel = labelFor(current);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"tenant-switcher-trigger\"\n aria-label={`Switch tenant (current: ${currentLabel})`}\n >\n {currentLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {available.map((tenant) => {\n const isCurrent = tenant.id === current.id;\n return (\n <DropdownMenuItem\n key={String(tenant.id)}\n data-testid={`tenant-switcher-option-${String(tenant.id)}`}\n disabled={isCurrent}\n onSelect={() => {\n router.post(buildUrl(tenant.id), {}, { preserveScroll: true });\n }}\n >\n {labelFor(tenant)}\n {isCurrent ? ' ✓' : ''}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/TenantSwitcher.tsx"],"names":[],"mappings":";;;;;;;;;;;AAkCA,IAAM,kBAAA,GAAqB,CAAC,EAAA,KAAgC,CAAA,eAAA,EAAkB,EAAE,CAAA,OAAA,CAAA;AAEzE,SAAS,cAAA,CAAe;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAC1C,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,IAAI,CAAC,OAAA,IAAW,SAAA,CAAU,MAAA,IAAU,GAAG,OAAO,IAAA;AAE9C,EAAA,MAAM,WAAW,SAAA,IAAa,kBAAA;AAC9B,EAAA,MAAM,WAAW,CAAC,MAAA,KAChB,OAAO,IAAA,EAAM,IAAA,KACT,MAAA,CAAO,IAAA,GACP,EAAE,sBAAA,EAAwB,CAAA,OAAA,EAAU,OAAO,EAAE,CAAA,CAAA,EAAI,EAAE,EAAA,EAAI,MAAA,CAAO,IAAI,CAAA;AACxE,EAAA,MAAM,YAAA,GAAe,SAAS,OAAO,CAAA;AAErC,EAAA,4BACG,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,SAAO,IAAA,EAC1B,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,OAAA;AAAA,QACR,IAAA,EAAK,IAAA;AAAA,QACL,aAAA,EAAY,yBAAA;AAAA,QACZ,YAAA,EAAY,CAAA,CAAE,0BAAA,EAA4B,CAAA,wBAAA,EAA2B,YAAY,CAAA,CAAA,CAAA,EAAK;AAAA,UACpF,MAAA,EAAQ;AAAA,SACT,CAAA;AAAA,QAEA,QAAA,EAAA;AAAA;AAAA,KACH,EACF,CAAA;AAAA,wBACC,mBAAA,EAAA,EAAoB,KAAA,EAAM,OACxB,QAAA,EAAA,SAAA,CAAU,GAAA,CAAI,CAAC,MAAA,KAAW;AACzB,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,EAAA,KAAO,OAAA,CAAQ,EAAA;AACxC,MAAA,uBACE,IAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UAEC,aAAA,EAAa,CAAA,uBAAA,EAA0B,MAAA,CAAO,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAAA,UACxD,QAAA,EAAU,SAAA;AAAA,UACV,UAAU,MAAM;AACd,YAAA,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG,EAAC,EAAG,EAAE,cAAA,EAAgB,IAAA,EAAM,CAAA;AAAA,UAC/D,CAAA;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,QAAA,CAAS,MAAM,CAAA;AAAA,YACf,YAAY,SAAA,GAAO;AAAA;AAAA,SAAA;AAAA,QARf,MAAA,CAAO,OAAO,EAAE;AAAA,OASvB;AAAA,IAEJ,CAAC,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ","file":"shell.js","sourcesContent":["/**\n * `<TenantSwitcher>` — dropdown that lists tenants the user can\n * access and dispatches `POST /admin/tenants/{id}/switch` via\n * Inertia router. Renders nothing when there is no current tenant\n * or the user only has access to one tenant.\n *\n * Mounts in the `tenantSwitcher` slot of `<Topbar>`. The current\n * tenant is read from `props.tenant.current` shared by the\n * server-side `HandleArqelInertiaRequests`; available tenants\n * come from the same payload.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { TenantSummary } from '@arqel-dev/types/tenant';\nimport { router } from '@inertiajs/react';\nimport type { JSX } from 'react';\nimport { Button } from '../action/Button.js';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../shadcn/ui/dropdown-menu.js';\n\nexport interface TenantSwitcherProps {\n current: TenantSummary | null;\n available: ReadonlyArray<TenantSummary>;\n /**\n * Path template for switching; defaults to\n * `/admin/tenants/{id}/switch`.\n */\n switchUrl?: (tenantId: string | number) => string;\n}\n\nconst DEFAULT_SWITCH_URL = (id: string | number): string => `/admin/tenants/${id}/switch`;\n\nexport function TenantSwitcher({\n current,\n available,\n switchUrl,\n}: TenantSwitcherProps): JSX.Element | null {\n const t = useArqelTranslations();\n if (!current || available.length <= 1) return null;\n\n const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;\n const labelFor = (tenant: TenantSummary): string =>\n tenant.name?.trim()\n ? tenant.name\n : t('arqel.tenant.unnamed', `Tenant ${tenant.id}`, { id: tenant.id });\n const currentLabel = labelFor(current);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"tenant-switcher-trigger\"\n aria-label={t('arqel.aria.tenant_switch', `Switch tenant (current: ${currentLabel})`, {\n tenant: currentLabel,\n })}\n >\n {currentLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {available.map((tenant) => {\n const isCurrent = tenant.id === current.id;\n return (\n <DropdownMenuItem\n key={String(tenant.id)}\n data-testid={`tenant-switcher-option-${String(tenant.id)}`}\n disabled={isCurrent}\n onSelect={() => {\n router.post(buildUrl(tenant.id), {}, { preserveScroll: true });\n }}\n >\n {labelFor(tenant)}\n {isCurrent ? ' ✓' : ''}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"]}
package/dist/table.js CHANGED
@@ -1,4 +1,4 @@
1
- export { DataTable, TableCell, TableFilters, TablePagination, TableToolbar } from './chunk-AZICSFBA.js';
1
+ export { DataTable, TableCell, TableFilters, TablePagination, TableToolbar } from './chunk-S5UNPCMQ.js';
2
2
  import './chunk-RMPOR2YZ.js';
3
3
  import './chunk-H23VX3RR.js';
4
4
  import './chunk-B7ULUJVO.js';
package/dist/utility.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Breadcrumbs, EmptyState, ErrorState, LoadingSkeleton } from './chunk-MTNFFSVA.js';
1
+ export { Breadcrumbs, EmptyState, ErrorState, LoadingSkeleton } from './chunk-SK6H7ARE.js';
2
2
  export { PageHeader } from './chunk-MXUXMHOK.js';
3
3
  import './chunk-B7ULUJVO.js';
4
4
  //# sourceMappingURL=utility.js.map
package/dist/widgets.js CHANGED
@@ -1,5 +1,5 @@
1
- export { ChartCard, DashboardFilters, DashboardGrid, TableCard, WidgetRenderer } from './chunk-HSDZM4AM.js';
2
- export { StatCard, WidgetWrapper } from './chunk-PSPJA5U6.js';
1
+ export { ChartCard, DashboardFilters, DashboardGrid, TableCard, WidgetRenderer } from './chunk-YYQ45W25.js';
2
+ export { StatCard, WidgetWrapper } from './chunk-WMOBLT3Z.js';
3
3
  import './chunk-B7ULUJVO.js';
4
4
  //# sourceMappingURL=widgets.js.map
5
5
  //# sourceMappingURL=widgets.js.map