@orianatech/pire 0.20.0 → 0.21.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.
Files changed (32) hide show
  1. package/dist/components/core/Badge.d.cts +14 -3
  2. package/dist/components/core/Badge.d.ts +14 -3
  3. package/dist/components/core/Badge.d.ts.map +1 -1
  4. package/dist/components/core/Tag.d.cts +8 -3
  5. package/dist/components/core/Tag.d.ts +8 -3
  6. package/dist/components/core/Tag.d.ts.map +1 -1
  7. package/dist/components/core/Text.d.cts +9 -4
  8. package/dist/components/core/Text.d.ts +9 -4
  9. package/dist/components/core/Text.d.ts.map +1 -1
  10. package/dist/components/data/DataTable.d.cts +9 -1
  11. package/dist/components/data/DataTable.d.ts +9 -1
  12. package/dist/components/data/DataTable.d.ts.map +1 -1
  13. package/dist/components/forms/ComboBox.d.cts +12 -2
  14. package/dist/components/forms/ComboBox.d.ts +12 -2
  15. package/dist/components/forms/ComboBox.d.ts.map +1 -1
  16. package/dist/components/forms/FileUpload.d.cts +10 -2
  17. package/dist/components/forms/FileUpload.d.ts +10 -2
  18. package/dist/components/forms/FileUpload.d.ts.map +1 -1
  19. package/dist/components/forms/NumberField.d.cts +17 -2
  20. package/dist/components/forms/NumberField.d.ts +17 -2
  21. package/dist/components/forms/NumberField.d.ts.map +1 -1
  22. package/dist/components/patterns/FileDropZone.d.cts +8 -1
  23. package/dist/components/patterns/FileDropZone.d.ts +8 -1
  24. package/dist/components/patterns/FileDropZone.d.ts.map +1 -1
  25. package/dist/i18n/messages.d.cts +2 -0
  26. package/dist/i18n/messages.d.ts +2 -0
  27. package/dist/i18n/messages.d.ts.map +1 -1
  28. package/dist/index.cjs +159 -92
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.js +181 -113
  31. package/dist/index.js.map +1 -1
  32. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -586,6 +586,7 @@ var IconButton = React3.forwardRef(function IconButton2({
586
586
  });
587
587
 
588
588
  // src/components/core/Badge.tsx
589
+ var React4 = __toESM(require("react"), 1);
589
590
  var import_jsx_runtime5 = require("react/jsx-runtime");
590
591
  var STATUS_ICON = {
591
592
  positive: "check-circle-2",
@@ -594,18 +595,19 @@ var STATUS_ICON = {
594
595
  informative: "info",
595
596
  neutral: "circle"
596
597
  };
597
- function Badge({ children, status = "neutral", showIcon = true, className, ...rest }) {
598
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: cx("pire-badge", className), "data-status": status, ...rest, children: [
598
+ var Badge = React4.forwardRef(function Badge2({ children, status = "neutral", showIcon = true, className, ...rest }, ref) {
599
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { ref, className: cx("pire-badge", className), "data-status": status, ...rest, children: [
599
600
  showIcon ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: STATUS_ICON[status], size: 12 }) : null,
600
601
  children
601
602
  ] });
602
- }
603
+ });
603
604
 
604
605
  // src/components/core/Tag.tsx
606
+ var React5 = __toESM(require("react"), 1);
605
607
  var import_react_aria_components4 = require("react-aria-components");
606
608
  var import_jsx_runtime6 = require("react/jsx-runtime");
607
- function Tag({ children, onRemove, isDisabled, category, className, ...rest }) {
608
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: cx("pire-tag", className), "data-disabled": isDisabled ? "true" : void 0, ...rest, children: [
609
+ var Tag = React5.forwardRef(function Tag2({ children, onRemove, isDisabled, category, className, ...rest }, ref) {
610
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { ref, className: cx("pire-tag", className), "data-disabled": isDisabled ? "true" : void 0, ...rest, children: [
609
611
  category ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "pire-tag-swatch", "data-category": category, "aria-hidden": "true" }) : null,
610
612
  children,
611
613
  onRemove ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -619,7 +621,7 @@ function Tag({ children, onRemove, isDisabled, category, className, ...rest }) {
619
621
  }
620
622
  ) : null
621
623
  ] });
622
- }
624
+ });
623
625
 
624
626
  // src/components/core/Card.tsx
625
627
  var import_jsx_runtime7 = require("react/jsx-runtime");
@@ -639,11 +641,11 @@ function Card({ title, subtitle, icon, actions, footer, interactive, children, c
639
641
  }
640
642
 
641
643
  // src/components/core/Avatar.tsx
642
- var React4 = __toESM(require("react"), 1);
644
+ var React6 = __toESM(require("react"), 1);
643
645
  var import_jsx_runtime8 = require("react/jsx-runtime");
644
646
  var initials = (name) => name.trim().split(/\s+/).slice(0, 2).map((p) => p[0]).join("").toUpperCase();
645
647
  function Avatar({ name, size = "md", src, className, ...rest }) {
646
- const [failed, setFailed] = React4.useState(false);
648
+ const [failed, setFailed] = React6.useState(false);
647
649
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: cx("pire-avatar", className), "data-size": size, role: "img", "aria-label": name, ...rest, children: src && !failed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
648
650
  "img",
649
651
  {
@@ -656,7 +658,7 @@ function Avatar({ name, size = "md", src, className, ...rest }) {
656
658
  }
657
659
 
658
660
  // src/components/core/SegmentedControl.tsx
659
- var React5 = __toESM(require("react"), 1);
661
+ var React7 = __toESM(require("react"), 1);
660
662
  var import_react_aria_components5 = require("react-aria-components");
661
663
  var import_jsx_runtime9 = require("react/jsx-runtime");
662
664
  function SegmentedControl({
@@ -670,7 +672,7 @@ function SegmentedControl({
670
672
  style,
671
673
  ...rest
672
674
  }) {
673
- const selected = React5.useMemo(() => new Set(value ? [value] : defaultValue ? [defaultValue] : []), [value, defaultValue]);
675
+ const selected = React7.useMemo(() => new Set(value ? [value] : defaultValue ? [defaultValue] : []), [value, defaultValue]);
674
676
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
675
677
  import_react_aria_components5.ToggleButtonGroup,
676
678
  {
@@ -704,8 +706,9 @@ function SegmentedControl({
704
706
  }
705
707
 
706
708
  // src/components/core/Text.tsx
709
+ var React8 = __toESM(require("react"), 1);
707
710
  var import_jsx_runtime10 = require("react/jsx-runtime");
708
- function Text({
711
+ var Text = React8.forwardRef(function Text2({
709
712
  size = "body",
710
713
  color = "primary",
711
714
  weight = "regular",
@@ -716,12 +719,13 @@ function Text({
716
719
  className,
717
720
  style,
718
721
  ...rest
719
- }) {
722
+ }, ref) {
720
723
  const lineClamp = typeof truncate === "number" ? truncate : truncate ? 1 : void 0;
721
724
  const clampStyle = lineClamp == null ? style : { ["--pire-text-clamp"]: lineClamp, ...style };
722
725
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
723
726
  Wrapper,
724
727
  {
728
+ ref,
725
729
  className: cx("pire-text", className),
726
730
  "data-size": size,
727
731
  "data-color": color,
@@ -733,10 +737,10 @@ function Text({
733
737
  ...rest
734
738
  }
735
739
  );
736
- }
737
- function Strong({ className, ...rest }) {
738
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { elementType: "span", weight: "strong", className, ...rest });
739
- }
740
+ });
741
+ var Strong = React8.forwardRef(function Strong2({ className, ...rest }, ref) {
742
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ref, elementType: "span", weight: "strong", className, ...rest });
743
+ });
740
744
 
741
745
  // src/components/core/Heading.tsx
742
746
  var import_react_aria_components6 = require("react-aria-components");
@@ -832,11 +836,11 @@ function FormField({ label, htmlFor, isRequired, hint, error, layout = "stacked"
832
836
  }
833
837
 
834
838
  // src/components/forms/Input.tsx
835
- var React7 = __toESM(require("react"), 1);
839
+ var React10 = __toESM(require("react"), 1);
836
840
  var import_react_aria_components9 = require("react-aria-components");
837
841
 
838
842
  // src/i18n/PireIntlProvider.tsx
839
- var React6 = __toESM(require("react"), 1);
843
+ var React9 = __toESM(require("react"), 1);
840
844
 
841
845
  // src/i18n/messages.ts
842
846
  var enMessages = {
@@ -847,6 +851,7 @@ var enMessages = {
847
851
  dataTableSelectRow: "Select row",
848
852
  dataTableLoading: "Loading records",
849
853
  dataTableSummaryRow: "Summary",
854
+ dataTableEmpty: "No records match the current filters.",
850
855
  dialogClose: "Close",
851
856
  sidePanelClose: "Close panel",
852
857
  inlineMessageDismiss: "Dismiss message",
@@ -906,6 +911,7 @@ var esMessages = {
906
911
  dataTableSelectRow: "Seleccionar fila",
907
912
  dataTableLoading: "Cargando registros",
908
913
  dataTableSummaryRow: "Resumen",
914
+ dataTableEmpty: "Ning\xFAn registro coincide con los filtros actuales.",
909
915
  dialogClose: "Cerrar",
910
916
  sidePanelClose: "Cerrar panel",
911
917
  inlineMessageDismiss: "Descartar mensaje",
@@ -960,19 +966,19 @@ var esMessages = {
960
966
 
961
967
  // src/i18n/PireIntlProvider.tsx
962
968
  var import_jsx_runtime16 = require("react/jsx-runtime");
963
- var MessagesContext = React6.createContext(enMessages);
969
+ var MessagesContext = React9.createContext(enMessages);
964
970
  function PireIntlProvider({ messages, children }) {
965
- const value = React6.useMemo(
971
+ const value = React9.useMemo(
966
972
  () => messages ? { ...enMessages, ...messages } : enMessages,
967
973
  [messages]
968
974
  );
969
975
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MessagesContext.Provider, { value, children });
970
976
  }
971
977
  function usePireMessages() {
972
- return React6.useContext(MessagesContext);
978
+ return React9.useContext(MessagesContext);
973
979
  }
974
980
  function useMessage(key, override) {
975
- const messages = React6.useContext(MessagesContext);
981
+ const messages = React9.useContext(MessagesContext);
976
982
  return override ?? messages[key];
977
983
  }
978
984
 
@@ -997,7 +1003,7 @@ function Input({
997
1003
  }) {
998
1004
  const msg = usePireMessages();
999
1005
  const isControlled = rest.value !== void 0;
1000
- const [ownValue, setOwnValue] = React7.useState(rest.defaultValue ?? "");
1006
+ const [ownValue, setOwnValue] = React10.useState(rest.defaultValue ?? "");
1001
1007
  const currentValue = isControlled ? rest.value : ownValue;
1002
1008
  const handleChange = (next) => {
1003
1009
  setOwnValue(next);
@@ -1044,10 +1050,10 @@ function Input({
1044
1050
  }
1045
1051
 
1046
1052
  // src/components/forms/TextArea.tsx
1047
- var React8 = __toESM(require("react"), 1);
1053
+ var React11 = __toESM(require("react"), 1);
1048
1054
  var import_react_aria_components10 = require("react-aria-components");
1049
1055
  var import_jsx_runtime18 = require("react/jsx-runtime");
1050
- var useIsomorphicLayoutEffect = typeof document === "undefined" ? React8.useEffect : React8.useLayoutEffect;
1056
+ var useIsomorphicLayoutEffect = typeof document === "undefined" ? React11.useEffect : React11.useLayoutEffect;
1051
1057
  function TextArea({
1052
1058
  label,
1053
1059
  description,
@@ -1063,13 +1069,13 @@ function TextArea({
1063
1069
  onChange,
1064
1070
  ...rest
1065
1071
  }) {
1066
- const innerRef = React8.useRef(null);
1067
- const ref = React8.useCallback((node) => {
1072
+ const innerRef = React11.useRef(null);
1073
+ const ref = React11.useCallback((node) => {
1068
1074
  innerRef.current = node;
1069
1075
  if (typeof textAreaRef === "function") textAreaRef(node);
1070
1076
  else if (textAreaRef) textAreaRef.current = node;
1071
1077
  }, [textAreaRef]);
1072
- const grow = React8.useCallback(() => {
1078
+ const grow = React11.useCallback(() => {
1073
1079
  const el = innerRef.current;
1074
1080
  if (!el || !autoGrow) return;
1075
1081
  const styles = getComputedStyle(el);
@@ -1241,6 +1247,7 @@ function Switch({ label, children, className, ...rest }) {
1241
1247
  }
1242
1248
 
1243
1249
  // src/components/forms/ComboBox.tsx
1250
+ var React12 = __toESM(require("react"), 1);
1244
1251
  var import_react_aria_components15 = require("react-aria-components");
1245
1252
  var import_jsx_runtime23 = require("react/jsx-runtime");
1246
1253
  var norm2 = (o) => typeof o === "string" ? { value: o, label: o } : o;
@@ -1260,6 +1267,8 @@ function ComboBox({
1260
1267
  isLoading,
1261
1268
  loadingLabel,
1262
1269
  emptyLabel,
1270
+ isClearable,
1271
+ clearLabel,
1263
1272
  onLoadMore,
1264
1273
  className,
1265
1274
  style,
@@ -1267,6 +1276,23 @@ function ComboBox({
1267
1276
  }) {
1268
1277
  const msg = usePireMessages();
1269
1278
  const items = options.map(norm2);
1279
+ const isSelectionControlled = value !== void 0;
1280
+ const [ownSelection, setOwnSelection] = React12.useState(defaultValue ?? null);
1281
+ const takesOverSelection = isClearable === true && !isSelectionControlled;
1282
+ const currentSelection = isSelectionControlled ? value : ownSelection;
1283
+ const [typedText, setTypedText] = React12.useState("");
1284
+ const currentText = inputValue !== void 0 ? inputValue : typedText;
1285
+ const handleInputChange = isClearable ? (text) => {
1286
+ setTypedText(text);
1287
+ onInputChange?.(text);
1288
+ } : onInputChange;
1289
+ const showsClear = isClearable && !rest.isDisabled && !rest.isReadOnly && (currentText !== "" || currentSelection != null);
1290
+ const clear = () => {
1291
+ setTypedText("");
1292
+ if (takesOverSelection) setOwnSelection(null);
1293
+ onChange?.(null);
1294
+ onInputChange?.("");
1295
+ };
1270
1296
  const collection = isFilteredExternally ? { items } : { defaultItems: items };
1271
1297
  const showsStatus = isLoading || isFilteredExternally && items.length === 0 && emptyLabel != null;
1272
1298
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
@@ -1274,14 +1300,16 @@ function ComboBox({
1274
1300
  {
1275
1301
  className: cx("pire-field", className),
1276
1302
  style,
1277
- selectedKey: value,
1278
- defaultSelectedKey: defaultValue,
1303
+ selectedKey: takesOverSelection ? ownSelection : value,
1304
+ defaultSelectedKey: takesOverSelection ? void 0 : defaultValue,
1279
1305
  onSelectionChange: (k) => {
1280
1306
  if (isLoading) return;
1281
- onChange?.(k == null ? null : String(k));
1307
+ const next = k == null ? null : String(k);
1308
+ if (takesOverSelection) setOwnSelection(next);
1309
+ onChange?.(next);
1282
1310
  },
1283
1311
  inputValue,
1284
- onInputChange,
1312
+ onInputChange: handleInputChange,
1285
1313
  ...collection,
1286
1314
  allowsEmptyCollection: isFilteredExternally || isLoading,
1287
1315
  menuTrigger: "input",
@@ -1302,6 +1330,7 @@ function ComboBox({
1302
1330
  children: [
1303
1331
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: "search", size: 16, className: "pire-leading-icon" }),
1304
1332
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_aria_components15.Input, { className: "pire-input", placeholder: rest.placeholder }),
1333
+ showsClear ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_aria_components15.Button, { className: "pire-input-clear", slot: null, onPress: clear, children: clearLabel ?? msg.inputClear }) : null,
1305
1334
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_aria_components15.Button, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.comboBoxShowSuggestions, style: { width: 20, height: 20 }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: "chevron-down", size: 16 }) })
1306
1335
  ]
1307
1336
  }
@@ -1329,7 +1358,7 @@ function ComboBox({
1329
1358
  }
1330
1359
 
1331
1360
  // src/components/forms/MultiComboBox.tsx
1332
- var React9 = __toESM(require("react"), 1);
1361
+ var React13 = __toESM(require("react"), 1);
1333
1362
  var import_react_aria_components16 = require("react-aria-components");
1334
1363
  var import_jsx_runtime24 = require("react/jsx-runtime");
1335
1364
  var norm3 = (o) => typeof o === "string" ? { value: o, label: o } : o;
@@ -1355,15 +1384,15 @@ function MultiComboBox({
1355
1384
  ...rest
1356
1385
  }) {
1357
1386
  const msg = usePireMessages();
1358
- const items = React9.useMemo(() => options.map(norm3), [options]);
1387
+ const items = React13.useMemo(() => options.map(norm3), [options]);
1359
1388
  const collection = isFilteredExternally ? { items } : { defaultItems: items };
1360
1389
  const showsStatus = isLoading || isFilteredExternally && items.length === 0 && emptyLabel != null;
1361
- const [uncontrolled, setUncontrolled] = React9.useState(defaultValue ?? []);
1362
- const [announcement, setAnnouncement] = React9.useState("");
1363
- const inputRef = React9.useRef(null);
1390
+ const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
1391
+ const [announcement, setAnnouncement] = React13.useState("");
1392
+ const inputRef = React13.useRef(null);
1364
1393
  const raw = value ?? uncontrolled;
1365
1394
  const contentKey = raw.join("\0");
1366
- const values = React9.useMemo(() => raw, [contentKey]);
1395
+ const values = React13.useMemo(() => raw, [contentKey]);
1367
1396
  const labelOf = (v) => items.find((o) => o.value === v)?.label ?? v;
1368
1397
  const isEditable = !rest.isDisabled && !rest.isReadOnly;
1369
1398
  const commit = (next) => {
@@ -1474,6 +1503,18 @@ function MultiComboBox({
1474
1503
  // src/components/forms/NumberField.tsx
1475
1504
  var import_react_aria_components17 = require("react-aria-components");
1476
1505
  var import_jsx_runtime25 = require("react/jsx-runtime");
1506
+ function decimalSeparatorFor(locale) {
1507
+ return new Intl.NumberFormat(locale).formatToParts(1.1).find((part) => part.type === "decimal")?.value ?? ".";
1508
+ }
1509
+ function typeIntoInput(el, text) {
1510
+ const start = el.selectionStart ?? el.value.length;
1511
+ const end = el.selectionEnd ?? start;
1512
+ const setValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
1513
+ setValue?.call(el, el.value.slice(0, start) + text + el.value.slice(end));
1514
+ el.dispatchEvent(new Event("input", { bubbles: true }));
1515
+ const caret = start + text.length;
1516
+ el.setSelectionRange(caret, caret);
1517
+ }
1477
1518
  function NumberField({
1478
1519
  label,
1479
1520
  suffix,
@@ -1487,6 +1528,25 @@ function NumberField({
1487
1528
  ...rest
1488
1529
  }) {
1489
1530
  const msg = usePireMessages();
1531
+ const { locale } = (0, import_react_aria_components17.useLocale)();
1532
+ const handleDecimalKey = (event) => {
1533
+ if (event.key !== "." || event.ctrlKey || event.metaKey || event.altKey) {
1534
+ return;
1535
+ }
1536
+ if (rest.isReadOnly || rest.isDisabled) {
1537
+ return;
1538
+ }
1539
+ const separator = decimalSeparatorFor(locale);
1540
+ if (separator === ".") {
1541
+ return;
1542
+ }
1543
+ const { maximumFractionDigits } = new Intl.NumberFormat(locale, rest.formatOptions).resolvedOptions();
1544
+ if (!maximumFractionDigits) {
1545
+ return;
1546
+ }
1547
+ event.preventDefault();
1548
+ typeIntoInput(event.currentTarget, separator);
1549
+ };
1490
1550
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_aria_components17.NumberField, { className: cx("pire-field", className), style, validationBehavior: "aria", ...rest, children: [
1491
1551
  label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_aria_components17.Label, { className: "pire-field-label", children: [
1492
1552
  label,
@@ -1501,7 +1561,7 @@ function NumberField({
1501
1561
  "data-invalid": rest.isInvalid ? "true" : void 0,
1502
1562
  "data-readonly": rest.isReadOnly ? "true" : void 0,
1503
1563
  children: [
1504
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Input, { className: "pire-input", "data-numeric": "true" }),
1564
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Input, { className: "pire-input", "data-numeric": "true", onKeyDown: handleDecimalKey }),
1505
1565
  suffix ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "pire-affix", children: suffix }) : null,
1506
1566
  hideStepper ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "pire-stepper", children: [
1507
1567
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Button, { slot: "increment", className: "pire-stepper-btn", "aria-label": msg.numberFieldIncrease, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { name: "plus", size: 10 }) }),
@@ -1679,13 +1739,13 @@ function DateRangePicker({
1679
1739
  }
1680
1740
 
1681
1741
  // src/components/forms/ValueHelpField.tsx
1682
- var React12 = __toESM(require("react"), 1);
1742
+ var React16 = __toESM(require("react"), 1);
1683
1743
 
1684
1744
  // src/components/patterns/ValueHelpDialog.tsx
1685
- var React11 = __toESM(require("react"), 1);
1745
+ var React15 = __toESM(require("react"), 1);
1686
1746
 
1687
1747
  // src/components/feedback/Dialog.tsx
1688
- var React10 = __toESM(require("react"), 1);
1748
+ var React14 = __toESM(require("react"), 1);
1689
1749
  var import_react_aria_components20 = require("react-aria-components");
1690
1750
  var import_jsx_runtime28 = require("react/jsx-runtime");
1691
1751
  function DialogTitle({ children, className }) {
@@ -1719,8 +1779,8 @@ function Dialog({
1719
1779
  onClose?.();
1720
1780
  onOpenChange?.(false);
1721
1781
  };
1722
- const parts = React10.Children.toArray(children);
1723
- const slotOf = (type) => parts.find((node) => React10.isValidElement(node) && node.type === type);
1782
+ const parts = React14.Children.toArray(children);
1783
+ const slotOf = (type) => parts.find((node) => React14.isValidElement(node) && node.type === type);
1724
1784
  const titleSlot = slotOf(DialogTitle);
1725
1785
  const descriptionSlot = slotOf(DialogDescription);
1726
1786
  const bodySlot = slotOf(DialogBody);
@@ -1816,7 +1876,7 @@ function DataTable({
1816
1876
  onSortChange,
1817
1877
  onRowAction,
1818
1878
  stickyHeader = true,
1819
- emptyLabel = "No records match the current filters.",
1879
+ emptyLabel,
1820
1880
  isLoading,
1821
1881
  loadingRowCount,
1822
1882
  loadingLabel,
@@ -1829,6 +1889,8 @@ function DataTable({
1829
1889
  ...rest
1830
1890
  }) {
1831
1891
  const msg = usePireMessages();
1892
+ const selectionMode = selectable === true || selectable === "multiple" ? "multiple" : selectable === "single" ? "single" : "none";
1893
+ const hasCheckboxColumn = selectionMode === "multiple";
1832
1894
  const sortDescriptor = sort ? { column: sort.key, direction: sort.dir === "asc" ? "ascending" : "descending" } : void 0;
1833
1895
  const handleSelection = (keys) => {
1834
1896
  if (keys === "all") return onSelectionChange?.(rows.map((r) => r.id));
@@ -1836,14 +1898,14 @@ function DataTable({
1836
1898
  };
1837
1899
  const skeletonRows = loadingRowCount ?? (rows.length || 5);
1838
1900
  const skeletonColumns = [
1839
- ...selectable ? [{ width: 44 }] : [],
1901
+ ...hasCheckboxColumn ? [{ width: 44 }] : [],
1840
1902
  ...columns.map((c) => ({ width: c.width, align: c.align, numeric: c.numeric }))
1841
1903
  ];
1842
1904
  const body = isLoading ? [] : rows;
1843
1905
  const presentation = new Map(rows.map((row) => [row.id, rowProps?.(row) ?? {}]));
1844
1906
  const disabledKeys = rows.filter((row) => presentation.get(row.id)?.isDisabled).map((row) => row.id);
1845
1907
  const expanded = new Set((expandedIds ?? []).map(String));
1846
- const spanAll = columns.length + (selectable ? 1 : 0);
1908
+ const spanAll = columns.length + (hasCheckboxColumn ? 1 : 0);
1847
1909
  const expandedKey = (id) => `${id}::__pire_expanded__`;
1848
1910
  return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1849
1911
  "div",
@@ -1860,7 +1922,7 @@ function DataTable({
1860
1922
  "data-sticky": String(stickyHeader),
1861
1923
  "aria-label": rest["aria-label"],
1862
1924
  disabledKeys: disabledKeys.length ? new Set(disabledKeys) : void 0,
1863
- selectionMode: selectable ? "multiple" : "none",
1925
+ selectionMode,
1864
1926
  selectedKeys: selected ? new Set(selected) : void 0,
1865
1927
  onSelectionChange: handleSelection,
1866
1928
  sortDescriptor,
@@ -1871,13 +1933,13 @@ function DataTable({
1871
1933
  } : void 0,
1872
1934
  children: [
1873
1935
  /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_react_aria_components21.TableHeader, { className: "pire-thead-row", children: [
1874
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Column, { className: "pire-th", width: 44, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectAll }) }) : null,
1936
+ hasCheckboxColumn ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Column, { className: "pire-th", width: 44, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectAll }) }) : null,
1875
1937
  columns.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1876
1938
  import_react_aria_components21.Column,
1877
1939
  {
1878
1940
  id: c.key,
1879
1941
  className: "pire-th",
1880
- isRowHeader: i === 0 && !selectable,
1942
+ isRowHeader: i === 0 && !hasCheckboxColumn,
1881
1943
  allowsSorting: c.sortable,
1882
1944
  width: c.width,
1883
1945
  "data-align": c.numeric || c.align === "right" ? "right" : c.align,
@@ -1903,7 +1965,7 @@ function DataTable({
1903
1965
  // biome-ignore lint/suspicious/noArrayIndexKey: placeholder rows are positional.
1904
1966
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(SkeletonTableRow, { columns: skeletonColumns, density }, i)
1905
1967
  ))
1906
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "pire-table-empty", children: emptyLabel }), children: body.flatMap((row) => {
1968
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "pire-table-empty", children: emptyLabel ?? msg.dataTableEmpty }), children: body.flatMap((row) => {
1907
1969
  const rowIsDisabled = presentation.get(row.id)?.isDisabled;
1908
1970
  const record = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1909
1971
  import_react_aria_components21.Row,
@@ -1912,7 +1974,7 @@ function DataTable({
1912
1974
  className: cx("pire-tr", presentation.get(row.id)?.className),
1913
1975
  "data-pressable": onRowAction && !rowIsDisabled ? "true" : void 0,
1914
1976
  children: [
1915
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Cell, { className: "pire-td", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectRow }) }) : null,
1977
+ hasCheckboxColumn ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Cell, { className: "pire-td", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectRow }) }) : null,
1916
1978
  columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1917
1979
  import_react_aria_components21.Cell,
1918
1980
  {
@@ -1931,14 +1993,14 @@ function DataTable({
1931
1993
  return [record, /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Row, { id: expandedKey(row.id), className: "pire-tr-expanded", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Cell, { className: "pire-td-expanded", colSpan: spanAll, children: renderExpanded(row) }) }, expandedKey(row.id))];
1932
1994
  }) }),
1933
1995
  footer && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.TableFooter, { className: "pire-tfoot", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_react_aria_components21.Row, { id: "__pire_footer__", className: "pire-tr-footer", children: [
1934
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Cell, { className: "pire-tf" }) : null,
1996
+ hasCheckboxColumn ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_aria_components21.Cell, { className: "pire-tf" }) : null,
1935
1997
  columns.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1936
1998
  import_react_aria_components21.Cell,
1937
1999
  {
1938
2000
  className: "pire-tf",
1939
2001
  "data-numeric": c.numeric ? "true" : void 0,
1940
2002
  style: { textAlign: c.align && !c.numeric ? c.align : void 0 },
1941
- children: footer[c.key] ?? (i === 0 && !selectable ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "pire-sr-only", children: msg.dataTableSummaryRow }) : null)
2003
+ children: footer[c.key] ?? (i === 0 && !hasCheckboxColumn ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "pire-sr-only", children: msg.dataTableSummaryRow }) : null)
1942
2004
  },
1943
2005
  c.key
1944
2006
  ))
@@ -1967,11 +2029,11 @@ function ValueHelpDialog({
1967
2029
  onClose
1968
2030
  }) {
1969
2031
  const msg = usePireMessages();
1970
- const [query, setQuery] = React11.useState("");
1971
- React11.useEffect(() => {
2032
+ const [query, setQuery] = React15.useState("");
2033
+ React15.useEffect(() => {
1972
2034
  if (isOpen) setQuery("");
1973
2035
  }, [isOpen]);
1974
- const filtered = React11.useMemo(() => {
2036
+ const filtered = React15.useMemo(() => {
1975
2037
  if (isFilteredExternally) return rows;
1976
2038
  const q = query.trim().toLowerCase();
1977
2039
  if (!q) return rows;
@@ -2053,7 +2115,7 @@ function ValueHelpField({
2053
2115
  style
2054
2116
  }) {
2055
2117
  const msg = usePireMessages();
2056
- const [open, setOpen] = React12.useState(false);
2118
+ const [open, setOpen] = React16.useState(false);
2057
2119
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cx(className), style, children: [
2058
2120
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2059
2121
  Input,
@@ -2109,7 +2171,7 @@ function ValueHelpField({
2109
2171
  }
2110
2172
 
2111
2173
  // src/components/forms/FileUpload.tsx
2112
- var React13 = __toESM(require("react"), 1);
2174
+ var React17 = __toESM(require("react"), 1);
2113
2175
  var import_react_aria_components23 = require("react-aria-components");
2114
2176
 
2115
2177
  // src/components/feedback/ProgressBar.tsx
@@ -2196,13 +2258,14 @@ function FileUpload({
2196
2258
  isRequired,
2197
2259
  fullWidth = true,
2198
2260
  className,
2199
- style
2261
+ style,
2262
+ ...rest
2200
2263
  }) {
2201
2264
  const msg = usePireMessages();
2202
- const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
2265
+ const [uncontrolled, setUncontrolled] = React17.useState(defaultValue ?? []);
2203
2266
  const files = value ?? uncontrolled;
2204
- const created = React13.useRef([]);
2205
- React13.useEffect(() => () => {
2267
+ const created = React17.useRef([]);
2268
+ React17.useEffect(() => () => {
2206
2269
  for (const url of created.current) URL.revokeObjectURL(url);
2207
2270
  }, []);
2208
2271
  const commit = (next) => {
@@ -2229,6 +2292,7 @@ function FileUpload({
2229
2292
  style,
2230
2293
  "data-full-width": String(fullWidth),
2231
2294
  "data-invalid": isInvalid ? "true" : void 0,
2295
+ ...rest,
2232
2296
  children: [
2233
2297
  label ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "pire-field-label", children: [
2234
2298
  label,
@@ -2313,7 +2377,7 @@ function ShellBar({
2313
2377
  }
2314
2378
 
2315
2379
  // src/components/navigation/SideNav.tsx
2316
- var React14 = __toESM(require("react"), 1);
2380
+ var React18 = __toESM(require("react"), 1);
2317
2381
  var import_react_aria_components26 = require("react-aria-components");
2318
2382
 
2319
2383
  // src/components/navigation/Menu.tsx
@@ -2400,10 +2464,10 @@ function SideNav({
2400
2464
  const msg = usePireMessages();
2401
2465
  const activeParent = findActiveParent(groups, value);
2402
2466
  const isControlled = expandedIds != null;
2403
- const [ownExpanded, setOwnExpanded] = React14.useState(
2467
+ const [ownExpanded, setOwnExpanded] = React18.useState(
2404
2468
  () => new Set(defaultExpandedIds ?? (activeParent ? [activeParent] : []))
2405
2469
  );
2406
- const [lastValue, setLastValue] = React14.useState(value);
2470
+ const [lastValue, setLastValue] = React18.useState(value);
2407
2471
  if (value !== lastValue) {
2408
2472
  setLastValue(value);
2409
2473
  if (!isControlled && activeParent && !ownExpanded.has(activeParent)) {
@@ -2667,7 +2731,7 @@ function InlineMessage({ kind = "info", title, action, onClose, children, classN
2667
2731
  }
2668
2732
 
2669
2733
  // src/components/feedback/Toast.tsx
2670
- var React15 = __toESM(require("react"), 1);
2734
+ var React19 = __toESM(require("react"), 1);
2671
2735
  var import_jsx_runtime42 = require("react/jsx-runtime");
2672
2736
  var KIND_ICON2 = {
2673
2737
  info: "info",
@@ -2693,26 +2757,26 @@ function Toast({ kind = "success", onClose, position = "bottom-center", children
2693
2757
  }
2694
2758
  );
2695
2759
  }
2696
- var ToastContext = React15.createContext(null);
2760
+ var ToastContext = React19.createContext(null);
2697
2761
  function ToastProvider({ children, timeout = 6e3 }) {
2698
2762
  const msg = usePireMessages();
2699
- const [toasts, setToasts] = React15.useState([]);
2700
- const close = React15.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
2701
- const add = React15.useCallback((toast) => {
2763
+ const [toasts, setToasts] = React19.useState([]);
2764
+ const close = React19.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
2765
+ const add = React19.useCallback((toast) => {
2702
2766
  const id = Math.random().toString(36).slice(2);
2703
2767
  setToasts((t) => [...t, { ...toast, id }]);
2704
2768
  const ms = toast.timeout ?? timeout;
2705
2769
  if (ms > 0) setTimeout(() => close(id), ms);
2706
2770
  return id;
2707
2771
  }, [close, timeout]);
2708
- const value = React15.useMemo(() => ({ add, close }), [add, close]);
2772
+ const value = React19.useMemo(() => ({ add, close }), [add, close]);
2709
2773
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(ToastContext.Provider, { value, children: [
2710
2774
  children,
2711
2775
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "pire-toast-region", role: "region", "aria-label": msg.toastRegionLabel, children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toast, { kind: t.kind, onClose: () => close(t.id), style: { position: "static", transform: "none" }, children: t.message }, t.id)) })
2712
2776
  ] });
2713
2777
  }
2714
2778
  function useToast() {
2715
- const ctx = React15.useContext(ToastContext);
2779
+ const ctx = React19.useContext(ToastContext);
2716
2780
  if (!ctx) throw new Error("useToast must be used inside <ToastProvider>");
2717
2781
  return ctx;
2718
2782
  }
@@ -3062,14 +3126,14 @@ function BarChart({
3062
3126
  }
3063
3127
 
3064
3128
  // src/components/data/LineChart.tsx
3065
- var React16 = __toESM(require("react"), 1);
3129
+ var React20 = __toESM(require("react"), 1);
3066
3130
  var import_jsx_runtime50 = require("react/jsx-runtime");
3067
3131
  var PLOT_INSET = { top: 10, right: 14, bottom: 24, left: 58 };
3068
3132
  var MARKER_LIMIT = 20;
3069
- var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React16.useEffect : React16.useLayoutEffect;
3133
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React20.useEffect : React20.useLayoutEffect;
3070
3134
  function useMeasuredWidth() {
3071
- const ref = React16.useRef(null);
3072
- const [width, setWidth] = React16.useState(0);
3135
+ const ref = React20.useRef(null);
3136
+ const [width, setWidth] = React20.useState(0);
3073
3137
  useIsomorphicLayoutEffect2(() => {
3074
3138
  const element = ref.current;
3075
3139
  if (!element) return;
@@ -3232,7 +3296,7 @@ function LineChart({
3232
3296
  }
3233
3297
 
3234
3298
  // src/components/data/DonutChart.tsx
3235
- var React17 = __toESM(require("react"), 1);
3299
+ var React21 = __toESM(require("react"), 1);
3236
3300
  var import_jsx_runtime51 = require("react/jsx-runtime");
3237
3301
  var SEGMENT_GAP_DEGREES = 1.5;
3238
3302
  function DonutChart({
@@ -3253,7 +3317,7 @@ function DonutChart({
3253
3317
  }) {
3254
3318
  const label = rest["aria-label"];
3255
3319
  const msg = usePireMessages();
3256
- const [hoveredIndex, setHoveredIndex] = React17.useState(null);
3320
+ const [hoveredIndex, setHoveredIndex] = React21.useState(null);
3257
3321
  warnOnDonutShape(series, categories.length, label);
3258
3322
  const values = (series[0]?.values ?? []).slice(0, categories.length);
3259
3323
  const segments = categories.map((category, index) => ({ category, index, value: values[index] ?? 0 })).filter((segment) => segment.value > 0);
@@ -3490,7 +3554,7 @@ function ConfirmDialog({
3490
3554
  }
3491
3555
 
3492
3556
  // src/components/patterns/CommandPalette.tsx
3493
- var React18 = __toESM(require("react"), 1);
3557
+ var React22 = __toESM(require("react"), 1);
3494
3558
  var import_react_aria_components31 = require("react-aria-components");
3495
3559
  var import_jsx_runtime60 = require("react/jsx-runtime");
3496
3560
  var RESULTS_SECTION_KEY = "__pire_results__";
@@ -3513,17 +3577,17 @@ function CommandPalette({
3513
3577
  style
3514
3578
  }) {
3515
3579
  const msg = usePireMessages();
3516
- const [query, setQuery] = React18.useState("");
3580
+ const [query, setQuery] = React22.useState("");
3517
3581
  const { contains } = (0, import_react_aria_components31.useFilter)({ sensitivity: "base" });
3518
- React18.useEffect(() => {
3582
+ React22.useEffect(() => {
3519
3583
  if (isOpen) setQuery("");
3520
3584
  }, [isOpen]);
3521
- const searchableById = React18.useMemo(() => {
3585
+ const searchableById = React22.useMemo(() => {
3522
3586
  const byId = /* @__PURE__ */ new Map();
3523
3587
  for (const group of groups) for (const item of group.items) byId.set(item.id, searchableText(item));
3524
3588
  return byId;
3525
3589
  }, [groups]);
3526
- const filter = React18.useCallback((textValue, inputValue, node) => {
3590
+ const filter = React22.useCallback((textValue, inputValue, node) => {
3527
3591
  if (node.parentKey === RESULTS_SECTION_KEY) return true;
3528
3592
  return contains(searchableById.get(String(node.key)) ?? textValue, inputValue);
3529
3593
  }, [contains, searchableById]);
@@ -3606,9 +3670,9 @@ function CommandPalette({
3606
3670
  );
3607
3671
  }
3608
3672
  function useCommandPaletteShortcut(onTrigger, { key = "k", isDisabled } = {}) {
3609
- const handler = React18.useRef(onTrigger);
3673
+ const handler = React22.useRef(onTrigger);
3610
3674
  handler.current = onTrigger;
3611
- React18.useEffect(() => {
3675
+ React22.useEffect(() => {
3612
3676
  if (isDisabled) return;
3613
3677
  const onKeyDown = (event) => {
3614
3678
  if (!(event.metaKey || event.ctrlKey) || event.altKey) return;
@@ -3662,7 +3726,7 @@ function EmptyState({ icon = "file-text", title, action, compact, children, clas
3662
3726
  }
3663
3727
 
3664
3728
  // src/components/patterns/FileDropZone.tsx
3665
- var React19 = __toESM(require("react"), 1);
3729
+ var React23 = __toESM(require("react"), 1);
3666
3730
  var import_react_aria_components33 = require("react-aria-components");
3667
3731
  var import_jsx_runtime63 = require("react/jsx-runtime");
3668
3732
  var isImage2 = (file) => file.type.startsWith("image/");
@@ -3687,13 +3751,15 @@ function FileDropZone({
3687
3751
  isRequired,
3688
3752
  fullWidth = true,
3689
3753
  className,
3690
- style
3754
+ style,
3755
+ "aria-label": ariaLabel,
3756
+ ...rest
3691
3757
  }) {
3692
3758
  const msg = usePireMessages();
3693
- const [uncontrolled, setUncontrolled] = React19.useState(defaultValue ?? []);
3759
+ const [uncontrolled, setUncontrolled] = React23.useState(defaultValue ?? []);
3694
3760
  const files = value ?? uncontrolled;
3695
- const created = React19.useRef([]);
3696
- React19.useEffect(() => () => {
3761
+ const created = React23.useRef([]);
3762
+ React23.useEffect(() => () => {
3697
3763
  for (const url of created.current) URL.revokeObjectURL(url);
3698
3764
  }, []);
3699
3765
  const commit = (next) => {
@@ -3713,7 +3779,7 @@ function FileDropZone({
3713
3779
  commit(allowsMultiple ? [...files, ...wrapped] : wrapped.slice(0, 1));
3714
3780
  };
3715
3781
  const remove = (target) => commit(files.filter((f) => f.file !== target));
3716
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
3782
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), ...rest, children: [
3717
3783
  label ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "pire-field-label", children: [
3718
3784
  label,
3719
3785
  isRequired ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
@@ -3722,6 +3788,7 @@ function FileDropZone({
3722
3788
  import_react_aria_components33.DropZone,
3723
3789
  {
3724
3790
  className: "pire-dropzone",
3791
+ "aria-label": ariaLabel,
3725
3792
  "data-height": height,
3726
3793
  isDisabled: isDisabled || isReadOnly,
3727
3794
  onDrop: async (e) => {