@aortl/admin-react 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1194,6 +1194,282 @@ function StatCard({ variant = "default", label, value, detail, icon, compact, bo
1194
1194
  });
1195
1195
  }
1196
1196
  //#endregion
1197
+ //#region src/chart-internal.ts
1198
+ /**
1199
+ * Multi-series palette — references EXISTING Flexoki palette tokens, NOT a new
1200
+ * token layer. Cycled by index (`SERIES[i % len]`); a datum's own `color`
1201
+ * overrides. Vanilla authors copy the same sequence (it's documented), so both
1202
+ * bundles render identical colours. Single-series charts ignore this entirely
1203
+ * and follow `currentColor`.
1204
+ */
1205
+ var SERIES = [
1206
+ "var(--color-blue-500)",
1207
+ "var(--color-orange-400)",
1208
+ "var(--color-green-500)",
1209
+ "var(--color-purple-400)",
1210
+ "var(--color-cyan-500)",
1211
+ "var(--color-magenta-400)",
1212
+ "var(--color-yellow-500)",
1213
+ "var(--color-red-400)"
1214
+ ];
1215
+ /** Resolve a segment's colour: explicit `datum.color` wins, else cycle SERIES. */
1216
+ function seriesColor(datum, index) {
1217
+ return datum.color ?? SERIES[index % SERIES.length];
1218
+ }
1219
+ /** Largest value, floored at 1 so the bar calc never divides by zero. */
1220
+ function computeMax(data, explicit) {
1221
+ if (explicit !== void 0) return explicit;
1222
+ return Math.max(1, ...data.map((d) => d.value));
1223
+ }
1224
+ /**
1225
+ * Build the cumulative `conic-gradient` stop string for a donut/pie:
1226
+ * `<color> <from>deg <to>deg, …`. Degrees accumulate across segments. A
1227
+ * non-positive total yields a single neutral fill so the ring isn't blank.
1228
+ */
1229
+ function buildDonutSegments(data) {
1230
+ const total = data.reduce((sum, d) => sum + Math.max(0, d.value), 0);
1231
+ if (total <= 0) return "var(--color-surface-strong) 0 100%";
1232
+ let acc = 0;
1233
+ const stops = [];
1234
+ for (let i = 0; i < data.length; i++) {
1235
+ const datum = data[i];
1236
+ const from = acc / total * 360;
1237
+ acc += Math.max(0, datum.value);
1238
+ const to = acc / total * 360;
1239
+ stops.push(`${seriesColor(datum, i)} ${from}deg ${to}deg`);
1240
+ }
1241
+ return stops.join(", ");
1242
+ }
1243
+ var TYPE_NOUN = {
1244
+ bar: "Bar chart",
1245
+ stack: "Proportion bar",
1246
+ donut: "Donut chart",
1247
+ pie: "Pie chart"
1248
+ };
1249
+ /**
1250
+ * Auto-generated summary for the chart root's `aria-label`. Callers that pass
1251
+ * their own `aria-label` skip this. Example: "Bar chart. Mon: 80, Tue: 52."
1252
+ */
1253
+ function buildAriaLabel(type, data) {
1254
+ const parts = data.map((d) => d.label !== void 0 ? `${d.label}: ${d.value}` : `${d.value}`);
1255
+ return `${TYPE_NOUN[type]}. ${parts.join(", ")}.`;
1256
+ }
1257
+ /** Native `title` text for a bar/segment/legend row. */
1258
+ function datumTitle(datum) {
1259
+ return datum.label !== void 0 ? `${datum.label}: ${datum.value}` : `${datum.value}`;
1260
+ }
1261
+ /** Merge admin custom-property vars with an incoming `style` (incoming wins). */
1262
+ function mergeStyle(vars, incoming) {
1263
+ return {
1264
+ ...vars,
1265
+ ...incoming
1266
+ };
1267
+ }
1268
+ //#endregion
1269
+ //#region src/BarChart.tsx
1270
+ /**
1271
+ * The bare bar-chart grid — no bars. Compose `<BarChart.Bar>` children by hand
1272
+ * (e.g. to interleave a reference line). Sets `role="img"`; pass `aria-label`.
1273
+ */
1274
+ function BarChartContainer({ orientation = "horizontal", size = "md", showValues, inline, variant = "primary", className, ...rest }) {
1275
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1276
+ role: "img",
1277
+ className: cn([
1278
+ "chart",
1279
+ "chart-bars",
1280
+ orientation === "vertical" && "chart-bars-vertical",
1281
+ size !== "md" && `chart-${size}`,
1282
+ showValues && "chart-values",
1283
+ inline && "chart-inline",
1284
+ variant !== "primary" && `chart-${variant}`
1285
+ ], className),
1286
+ ...rest
1287
+ });
1288
+ }
1289
+ /**
1290
+ * One bar. Renders a label (only when present), the fill (with a native
1291
+ * `title`), and an always-present value cell (hidden by CSS unless the chart
1292
+ * carries `.chart-values`). Stays `currentColor` unless an explicit colour is
1293
+ * given — single-series bars never cycle the SERIES palette.
1294
+ */
1295
+ function Bar({ datum, value, label, color, className, style, ...rest }) {
1296
+ const v = datum?.value ?? value ?? 0;
1297
+ const lab = datum?.label ?? label;
1298
+ const barColor = datum?.color ?? color;
1299
+ const vars = { "--value": v };
1300
+ if (barColor !== void 0) vars["--bar-color"] = barColor;
1301
+ const title = datum !== void 0 ? datumTitle(datum) : void 0;
1302
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1303
+ className: cn("chart-bar", className),
1304
+ style: mergeStyle(vars, style),
1305
+ ...rest,
1306
+ children: [
1307
+ lab !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1308
+ className: cn("chart-bar-label", void 0),
1309
+ children: lab
1310
+ }) : null,
1311
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1312
+ className: cn("chart-bar-track", void 0),
1313
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1314
+ className: cn("chart-bar-fill", void 0),
1315
+ title
1316
+ })
1317
+ }),
1318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1319
+ className: cn("chart-bar-value", void 0),
1320
+ children: v
1321
+ })
1322
+ ]
1323
+ });
1324
+ }
1325
+ /**
1326
+ * Single-series bar chart. Computes the max, sets `--chart-max` on the
1327
+ * container (bars inherit it), and generates an overridable `aria-label`.
1328
+ * Horizontal by default; pass `orientation="vertical"` for columns. For
1329
+ * hand-composed layouts use `<BarChart.Container>` + `<BarChart.Bar>`.
1330
+ */
1331
+ function BarChartRoot({ data, max, orientation = "horizontal", size = "md", showValues, inline, variant = "primary", style, "aria-label": ariaLabel, ...rest }) {
1332
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarChartContainer, {
1333
+ orientation,
1334
+ size,
1335
+ showValues,
1336
+ inline,
1337
+ variant,
1338
+ style: mergeStyle({ "--chart-max": computeMax(data, max) }, style),
1339
+ "aria-label": ariaLabel ?? buildAriaLabel("bar", data),
1340
+ ...rest,
1341
+ children: data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, { datum: d }, d.label ?? i))
1342
+ });
1343
+ }
1344
+ var BarChart = Object.assign(BarChartRoot, {
1345
+ Container: BarChartContainer,
1346
+ Bar
1347
+ });
1348
+ //#endregion
1349
+ //#region src/ChartLegend.tsx
1350
+ /**
1351
+ * Shared legend for `<Donut>` and `<StackedBar>` — one swatch + label per
1352
+ * datum. Each row carries its own `title`, which is where the donut's
1353
+ * per-slice read-out lives (a conic-gradient slice has no element to hang a
1354
+ * `title` on). The swatch colour mirrors `seriesColor`, so legend and chart
1355
+ * stay in sync.
1356
+ */
1357
+ function ChartLegend({ data, className, ...rest }) {
1358
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1359
+ className: cn("chart-legend", className),
1360
+ ...rest,
1361
+ children: data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
1362
+ className: cn("chart-legend-item", void 0),
1363
+ style: mergeStyle({ "--legend-color": seriesColor(d, i) }),
1364
+ title: datumTitle(d),
1365
+ children: d.label ?? d.value
1366
+ }, d.label ?? i))
1367
+ });
1368
+ }
1369
+ //#endregion
1370
+ //#region src/Donut.tsx
1371
+ /** Square positioning context that overlays the centre label on the ring. */
1372
+ function Figure({ size = "md", className, ...rest }) {
1373
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1374
+ className: cn(["chart-donut-figure", size !== "md" && `chart-${size}`], className),
1375
+ ...rest
1376
+ });
1377
+ }
1378
+ /** The masked conic-gradient ring. Builds `--donut-segments` from the data. */
1379
+ function Ring({ data, pie, thickness, className, style, ...rest }) {
1380
+ const vars = { "--donut-segments": buildDonutSegments(data) };
1381
+ if (thickness !== void 0 && !pie) vars["--donut-thickness"] = thickness;
1382
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1383
+ className: cn(["chart-donut", pie && "chart-donut-pie"], className),
1384
+ style: mergeStyle(vars, style),
1385
+ ...rest
1386
+ });
1387
+ }
1388
+ /** Centred overlay (a total, a label). Not a child of the ring — masks clip subtrees. */
1389
+ function Center({ className, ...rest }) {
1390
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1391
+ className: cn("chart-donut-center", className),
1392
+ ...rest
1393
+ });
1394
+ }
1395
+ /**
1396
+ * Donut (or `pie`) breakdown. Builds the cumulative conic-gradient string from
1397
+ * `data`, overlays an optional `centerLabel`, and generates an overridable
1398
+ * `aria-label`. Per-slice read-outs live on the optional `legend` rows — a
1399
+ * conic slice has no element to carry a `title`. Resize by overriding
1400
+ * `--chart-size` (it inherits to the figure) or via `size`.
1401
+ */
1402
+ function DonutRoot({ data, size = "md", thickness, pie, centerLabel, legend, inline, className, "aria-label": ariaLabel, ...rest }) {
1403
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1404
+ role: "img",
1405
+ className: cn(["chart", inline && "chart-inline"], className),
1406
+ "aria-label": ariaLabel ?? buildAriaLabel(pie ? "pie" : "donut", data),
1407
+ ...rest,
1408
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Figure, {
1409
+ size,
1410
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Ring, {
1411
+ data,
1412
+ pie,
1413
+ thickness
1414
+ }), centerLabel !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, { children: centerLabel }) : null]
1415
+ }), legend ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartLegend, { data }) : null]
1416
+ });
1417
+ }
1418
+ var Donut = Object.assign(DonutRoot, {
1419
+ Figure,
1420
+ Ring,
1421
+ Center,
1422
+ Legend: ChartLegend
1423
+ });
1424
+ //#endregion
1425
+ //#region src/StackedBar.tsx
1426
+ /** The bare proportion track — compose `<StackedBar.Segment>` children by hand. */
1427
+ function Track({ className, ...rest }) {
1428
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1429
+ className: cn("chart-stack", className),
1430
+ ...rest
1431
+ });
1432
+ }
1433
+ /**
1434
+ * One proportion segment, sized by `flex: var(--value)`. Multi-series by
1435
+ * default: takes its colour from `seriesColor` (SERIES cycle or `datum.color`).
1436
+ */
1437
+ function Segment({ datum, index = 0, value, color, className, style, ...rest }) {
1438
+ const v = datum?.value ?? value ?? 0;
1439
+ const segColor = datum !== void 0 ? seriesColor(datum, index) : color;
1440
+ const vars = { "--value": v };
1441
+ if (segColor !== void 0) vars["--segment-color"] = segColor;
1442
+ const title = datum !== void 0 ? datumTitle(datum) : void 0;
1443
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1444
+ className: cn("chart-segment", className),
1445
+ style: mergeStyle(vars, style),
1446
+ title,
1447
+ ...rest
1448
+ });
1449
+ }
1450
+ /**
1451
+ * Single horizontal proportion bar — a "60% A / 30% B / 10% C" breakdown.
1452
+ * Segments are sized by their flex ratios (no max needed) and coloured from the
1453
+ * SERIES palette by default. Generates an overridable `aria-label`.
1454
+ */
1455
+ function StackedBarRoot({ data, legend, inline, className, "aria-label": ariaLabel, ...rest }) {
1456
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1457
+ role: "img",
1458
+ className: cn(["chart", inline && "chart-inline"], className),
1459
+ "aria-label": ariaLabel ?? buildAriaLabel("stack", data),
1460
+ ...rest,
1461
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Track, { children: data.map((d, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Segment, {
1462
+ datum: d,
1463
+ index: i
1464
+ }, d.label ?? i)) }), legend ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartLegend, { data }) : null]
1465
+ });
1466
+ }
1467
+ var StackedBar = Object.assign(StackedBarRoot, {
1468
+ Track,
1469
+ Segment,
1470
+ Legend: ChartLegend
1471
+ });
1472
+ //#endregion
1197
1473
  //#region src/Dialog.tsx
1198
1474
  var DialogContext = (0, react.createContext)(null);
1199
1475
  function DefaultCloseIcon() {
@@ -2012,15 +2288,18 @@ exports.AdminRoot = AdminRoot;
2012
2288
  exports.Alert = Alert;
2013
2289
  exports.AppShell = AppShell;
2014
2290
  exports.Badge = Badge;
2291
+ exports.BarChart = BarChart;
2015
2292
  exports.BrandTile = BrandTile;
2016
2293
  exports.Breadcrumbs = Breadcrumbs;
2017
2294
  exports.Button = Button;
2018
2295
  exports.ButtonGroup = ButtonGroup;
2019
2296
  exports.Card = Card;
2297
+ exports.ChartLegend = ChartLegend;
2020
2298
  exports.Checkbox = Checkbox;
2021
2299
  exports.CodeBlock = CodeBlock;
2022
2300
  exports.Container = Container;
2023
2301
  exports.Dialog = Dialog;
2302
+ exports.Donut = Donut;
2024
2303
  exports.Field = Field;
2025
2304
  exports.FileInput = FileInput;
2026
2305
  exports.Footer = Footer;
@@ -2036,9 +2315,11 @@ exports.Progress = Progress;
2036
2315
  exports.PropertyList = PropertyList;
2037
2316
  exports.Radio = Radio;
2038
2317
  exports.RadioGroup = RadioGroup;
2318
+ exports.SERIES = SERIES;
2039
2319
  exports.Select = Select;
2040
2320
  exports.Sidebar = Sidebar;
2041
2321
  exports.Spinner = Spinner;
2322
+ exports.StackedBar = StackedBar;
2042
2323
  exports.StatCard = StatCard;
2043
2324
  exports.Switch = Switch;
2044
2325
  exports.Table = Table;