@orianatech/pire 0.15.0 → 0.17.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.js CHANGED
@@ -405,15 +405,17 @@ var Button = React.forwardRef(function Button2({ children, variant = "secondary"
405
405
  });
406
406
 
407
407
  // src/components/core/IconButton.tsx
408
- import * as React2 from "react";
408
+ import * as React3 from "react";
409
409
  import { Button as AriaButton2 } from "react-aria-components";
410
410
 
411
411
  // src/components/feedback/Tooltip.tsx
412
- import { TooltipTrigger, Tooltip as AriaTooltip, OverlayArrow } from "react-aria-components";
412
+ import * as React2 from "react";
413
+ import { TooltipTrigger, Tooltip as AriaTooltip, OverlayArrow, Focusable } from "react-aria-components";
413
414
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
414
415
  function Tooltip({ label, placement = "top", delay = 500, children }) {
416
+ const target = React2.isValidElement(children) ? React2.cloneElement(children, { className: cx(children.props.className, "pire-tooltip-target") }) : /* @__PURE__ */ jsx3("span", { className: "pire-tooltip-target", children });
415
417
  return /* @__PURE__ */ jsxs2(TooltipTrigger, { delay, closeDelay: 0, children: [
416
- children,
418
+ /* @__PURE__ */ jsx3(Focusable, { children: target }),
417
419
  /* @__PURE__ */ jsxs2(AriaTooltip, { className: "pire-tooltip", placement, offset: 6, children: [
418
420
  /* @__PURE__ */ jsx3(OverlayArrow, { children: /* @__PURE__ */ jsx3("span", {}) }),
419
421
  label
@@ -423,7 +425,7 @@ function Tooltip({ label, placement = "top", delay = 500, children }) {
423
425
 
424
426
  // src/components/core/IconButton.tsx
425
427
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
426
- var IconButton = React2.forwardRef(function IconButton2({
428
+ var IconButton = React3.forwardRef(function IconButton2({
427
429
  icon,
428
430
  label,
429
431
  size = "md",
@@ -511,11 +513,11 @@ function Card({ title, subtitle, icon, actions, footer, interactive, children, c
511
513
  }
512
514
 
513
515
  // src/components/core/Avatar.tsx
514
- import * as React3 from "react";
516
+ import * as React4 from "react";
515
517
  import { jsx as jsx8 } from "react/jsx-runtime";
516
518
  var initials = (name) => name.trim().split(/\s+/).slice(0, 2).map((p) => p[0]).join("").toUpperCase();
517
519
  function Avatar({ name, size = "md", src, className, ...rest }) {
518
- const [failed, setFailed] = React3.useState(false);
520
+ const [failed, setFailed] = React4.useState(false);
519
521
  return /* @__PURE__ */ jsx8("span", { className: cx("pire-avatar", className), "data-size": size, role: "img", "aria-label": name, ...rest, children: src && !failed ? /* @__PURE__ */ jsx8(
520
522
  "img",
521
523
  {
@@ -528,7 +530,7 @@ function Avatar({ name, size = "md", src, className, ...rest }) {
528
530
  }
529
531
 
530
532
  // src/components/core/SegmentedControl.tsx
531
- import * as React4 from "react";
533
+ import * as React5 from "react";
532
534
  import { ToggleButtonGroup, ToggleButton } from "react-aria-components";
533
535
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
534
536
  function SegmentedControl({
@@ -542,7 +544,7 @@ function SegmentedControl({
542
544
  style,
543
545
  ...rest
544
546
  }) {
545
- const selected = React4.useMemo(() => new Set(value ? [value] : defaultValue ? [defaultValue] : []), [value, defaultValue]);
547
+ const selected = React5.useMemo(() => new Set(value ? [value] : defaultValue ? [defaultValue] : []), [value, defaultValue]);
546
548
  return /* @__PURE__ */ jsx9(
547
549
  ToggleButtonGroup,
548
550
  {
@@ -704,154 +706,15 @@ function FormField({ label, htmlFor, isRequired, hint, error, layout = "stacked"
704
706
  }
705
707
 
706
708
  // src/components/forms/Input.tsx
707
- import { TextField, Label, Input as AriaInput, Group, Text as Text2, FieldError } from "react-aria-components";
708
- import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
709
- function Input({
710
- label,
711
- icon,
712
- suffix,
713
- description,
714
- errorMessage,
715
- size = "md",
716
- numeric,
717
- fullWidth = true,
718
- className,
719
- style,
720
- inputRef,
721
- onChange,
722
- ...rest
723
- }) {
724
- return /* @__PURE__ */ jsxs10(
725
- TextField,
726
- {
727
- className: cx("pire-field", className),
728
- style,
729
- onChange,
730
- validationBehavior: "aria",
731
- ...rest,
732
- children: [
733
- label ? /* @__PURE__ */ jsxs10(Label, { className: "pire-field-label", children: [
734
- label,
735
- rest.isRequired ? /* @__PURE__ */ jsx16("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
736
- ] }) : null,
737
- /* @__PURE__ */ jsxs10(
738
- Group,
739
- {
740
- className: "pire-control",
741
- "data-size": size,
742
- "data-full-width": String(fullWidth),
743
- "data-invalid": rest.isInvalid ? "true" : void 0,
744
- "data-readonly": rest.isReadOnly ? "true" : void 0,
745
- children: [
746
- icon ? /* @__PURE__ */ jsx16(Icon, { name: icon, size: 16, className: "pire-leading-icon" }) : null,
747
- /* @__PURE__ */ jsx16(AriaInput, { ref: inputRef, className: "pire-input", "data-numeric": numeric ? "true" : void 0 }),
748
- suffix ? /* @__PURE__ */ jsx16("span", { className: "pire-affix", children: suffix }) : null
749
- ]
750
- }
751
- ),
752
- description ? /* @__PURE__ */ jsx16(Text2, { slot: "description", className: "pire-field-hint", children: description }) : null,
753
- /* @__PURE__ */ jsx16(FieldError, { className: "pire-field-error", children: errorMessage })
754
- ]
755
- }
756
- );
757
- }
758
-
759
- // src/components/forms/TextArea.tsx
760
- import * as React5 from "react";
761
- import { TextField as TextField2, Label as Label2, TextArea as AriaTextArea, Group as Group2, Text as Text3, FieldError as FieldError2 } from "react-aria-components";
762
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
763
- var useIsomorphicLayoutEffect = typeof document === "undefined" ? React5.useEffect : React5.useLayoutEffect;
764
- function TextArea({
765
- label,
766
- description,
767
- errorMessage,
768
- size = "md",
769
- rows = 3,
770
- autoGrow,
771
- maxRows,
772
- fullWidth = true,
773
- className,
774
- style,
775
- textAreaRef,
776
- onChange,
777
- ...rest
778
- }) {
779
- const innerRef = React5.useRef(null);
780
- const ref = React5.useCallback((node) => {
781
- innerRef.current = node;
782
- if (typeof textAreaRef === "function") textAreaRef(node);
783
- else if (textAreaRef) textAreaRef.current = node;
784
- }, [textAreaRef]);
785
- const grow = React5.useCallback(() => {
786
- const el = innerRef.current;
787
- if (!el || !autoGrow) return;
788
- const styles = getComputedStyle(el);
789
- const lineHeight = Number.parseFloat(styles.lineHeight) || Number.parseFloat(styles.fontSize) * 1.5;
790
- const chrome = el.offsetHeight - el.clientHeight;
791
- el.style.height = "auto";
792
- const wanted = maxRows ? Math.min(el.scrollHeight, Math.ceil(lineHeight * maxRows)) : el.scrollHeight;
793
- const next = `${wanted + chrome}px`;
794
- if (el.style.height !== next) el.style.height = next;
795
- }, [autoGrow, maxRows]);
796
- useIsomorphicLayoutEffect(() => {
797
- if (!autoGrow) {
798
- if (innerRef.current) innerRef.current.style.height = "";
799
- return;
800
- }
801
- grow();
802
- }, [autoGrow, grow, rest.value]);
803
- return /* @__PURE__ */ jsxs11(
804
- TextField2,
805
- {
806
- className: cx("pire-field", className),
807
- style,
808
- onChange,
809
- validationBehavior: "aria",
810
- ...rest,
811
- children: [
812
- label ? /* @__PURE__ */ jsxs11(Label2, { className: "pire-field-label", children: [
813
- label,
814
- rest.isRequired ? /* @__PURE__ */ jsx17("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
815
- ] }) : null,
816
- /* @__PURE__ */ jsx17(
817
- Group2,
818
- {
819
- className: "pire-control",
820
- "data-size": size,
821
- "data-full-width": String(fullWidth),
822
- "data-multiline": "true",
823
- "data-invalid": rest.isInvalid ? "true" : void 0,
824
- "data-readonly": rest.isReadOnly ? "true" : void 0,
825
- children: /* @__PURE__ */ jsx17(
826
- AriaTextArea,
827
- {
828
- ref,
829
- rows,
830
- onInput: autoGrow ? grow : void 0,
831
- className: cx("pire-input", "pire-textarea"),
832
- "data-auto-grow": autoGrow ? "true" : void 0
833
- }
834
- )
835
- }
836
- ),
837
- description ? /* @__PURE__ */ jsx17(Text3, { slot: "description", className: "pire-field-hint", children: description }) : null,
838
- /* @__PURE__ */ jsx17(FieldError2, { className: "pire-field-error", children: errorMessage })
839
- ]
840
- }
841
- );
842
- }
843
-
844
- // src/components/forms/Select.tsx
709
+ import * as React7 from "react";
845
710
  import {
846
- Select as AriaSelect,
847
- Label as Label3,
848
- Button as AriaButton4,
849
- SelectValue,
850
- Popover,
851
- ListBox,
852
- ListBoxItem,
853
- Text as Text4,
854
- FieldError as FieldError3
711
+ TextField,
712
+ Label,
713
+ Input as AriaInput,
714
+ Group,
715
+ Text as Text2,
716
+ FieldError,
717
+ Button as AriaButton4
855
718
  } from "react-aria-components";
856
719
 
857
720
  // src/i18n/PireIntlProvider.tsx
@@ -865,6 +728,7 @@ var enMessages = {
865
728
  dataTableSelectAll: "Select all rows",
866
729
  dataTableSelectRow: "Select row",
867
730
  dataTableLoading: "Loading records",
731
+ dataTableSummaryRow: "Summary",
868
732
  dialogClose: "Close",
869
733
  sidePanelClose: "Close panel",
870
734
  inlineMessageDismiss: "Dismiss message",
@@ -879,6 +743,7 @@ var enMessages = {
879
743
  dateRangePresetsLabel: "Date range shortcuts",
880
744
  numberFieldIncrease: "Increase",
881
745
  numberFieldDecrease: "Decrease",
746
+ inputClear: "Clear",
882
747
  valueHelpFieldPlaceholder: "Not selected",
883
748
  valueHelpFieldClear: "Clear selection",
884
749
  valueHelpFieldOpenNamed: "Select {label}",
@@ -919,6 +784,7 @@ var esMessages = {
919
784
  dataTableSelectAll: "Seleccionar todas las filas",
920
785
  dataTableSelectRow: "Seleccionar fila",
921
786
  dataTableLoading: "Cargando registros",
787
+ dataTableSummaryRow: "Resumen",
922
788
  dialogClose: "Cerrar",
923
789
  sidePanelClose: "Cerrar panel",
924
790
  inlineMessageDismiss: "Descartar mensaje",
@@ -933,6 +799,7 @@ var esMessages = {
933
799
  dateRangePresetsLabel: "Atajos de rango de fechas",
934
800
  numberFieldIncrease: "Aumentar",
935
801
  numberFieldDecrease: "Disminuir",
802
+ inputClear: "Limpiar",
936
803
  valueHelpFieldPlaceholder: "Sin seleccionar",
937
804
  valueHelpFieldClear: "Limpiar selecci\xF3n",
938
805
  valueHelpFieldOpenNamed: "Seleccionar {label}",
@@ -968,14 +835,14 @@ var esMessages = {
968
835
  };
969
836
 
970
837
  // src/i18n/PireIntlProvider.tsx
971
- import { jsx as jsx18 } from "react/jsx-runtime";
838
+ import { jsx as jsx16 } from "react/jsx-runtime";
972
839
  var MessagesContext = React6.createContext(enMessages);
973
840
  function PireIntlProvider({ messages, children }) {
974
841
  const value = React6.useMemo(
975
842
  () => messages ? { ...enMessages, ...messages } : enMessages,
976
843
  [messages]
977
844
  );
978
- return /* @__PURE__ */ jsx18(MessagesContext.Provider, { value, children });
845
+ return /* @__PURE__ */ jsx16(MessagesContext.Provider, { value, children });
979
846
  }
980
847
  function usePireMessages() {
981
848
  return React6.useContext(MessagesContext);
@@ -985,7 +852,170 @@ function useMessage(key, override) {
985
852
  return override ?? messages[key];
986
853
  }
987
854
 
855
+ // src/components/forms/Input.tsx
856
+ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
857
+ function Input({
858
+ label,
859
+ icon,
860
+ suffix,
861
+ description,
862
+ errorMessage,
863
+ size = "md",
864
+ numeric,
865
+ isClearable,
866
+ clearLabel,
867
+ fullWidth = true,
868
+ className,
869
+ style,
870
+ inputRef,
871
+ onChange,
872
+ ...rest
873
+ }) {
874
+ const msg = usePireMessages();
875
+ const isControlled = rest.value !== void 0;
876
+ const [ownValue, setOwnValue] = React7.useState(rest.defaultValue ?? "");
877
+ const currentValue = isControlled ? rest.value : ownValue;
878
+ const handleChange = (next) => {
879
+ setOwnValue(next);
880
+ onChange?.(next);
881
+ };
882
+ const takesOverValue = isClearable && !isControlled;
883
+ const valueProps = takesOverValue ? { value: ownValue, defaultValue: void 0 } : {};
884
+ const showsClear = isClearable && currentValue !== "" && !rest.isDisabled && !rest.isReadOnly;
885
+ return /* @__PURE__ */ jsxs10(
886
+ TextField,
887
+ {
888
+ className: cx("pire-field", className),
889
+ style,
890
+ onChange: handleChange,
891
+ validationBehavior: "aria",
892
+ ...rest,
893
+ ...valueProps,
894
+ children: [
895
+ label ? /* @__PURE__ */ jsxs10(Label, { className: "pire-field-label", children: [
896
+ label,
897
+ rest.isRequired ? /* @__PURE__ */ jsx17("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
898
+ ] }) : null,
899
+ /* @__PURE__ */ jsxs10(
900
+ Group,
901
+ {
902
+ className: "pire-control",
903
+ "data-size": size,
904
+ "data-full-width": String(fullWidth),
905
+ "data-invalid": rest.isInvalid ? "true" : void 0,
906
+ "data-readonly": rest.isReadOnly ? "true" : void 0,
907
+ children: [
908
+ icon ? /* @__PURE__ */ jsx17(Icon, { name: icon, size: 16, className: "pire-leading-icon" }) : null,
909
+ /* @__PURE__ */ jsx17(AriaInput, { ref: inputRef, className: "pire-input", "data-numeric": numeric ? "true" : void 0 }),
910
+ showsClear ? /* @__PURE__ */ jsx17(AriaButton4, { className: "pire-input-clear", onPress: () => handleChange(""), children: clearLabel ?? msg.inputClear }) : null,
911
+ suffix ? /* @__PURE__ */ jsx17("span", { className: "pire-affix", children: suffix }) : null
912
+ ]
913
+ }
914
+ ),
915
+ description ? /* @__PURE__ */ jsx17(Text2, { slot: "description", className: "pire-field-hint", children: description }) : null,
916
+ /* @__PURE__ */ jsx17(FieldError, { className: "pire-field-error", children: errorMessage })
917
+ ]
918
+ }
919
+ );
920
+ }
921
+
922
+ // src/components/forms/TextArea.tsx
923
+ import * as React8 from "react";
924
+ import { TextField as TextField2, Label as Label2, TextArea as AriaTextArea, Group as Group2, Text as Text3, FieldError as FieldError2 } from "react-aria-components";
925
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
926
+ var useIsomorphicLayoutEffect = typeof document === "undefined" ? React8.useEffect : React8.useLayoutEffect;
927
+ function TextArea({
928
+ label,
929
+ description,
930
+ errorMessage,
931
+ size = "md",
932
+ rows = 3,
933
+ autoGrow,
934
+ maxRows,
935
+ fullWidth = true,
936
+ className,
937
+ style,
938
+ textAreaRef,
939
+ onChange,
940
+ ...rest
941
+ }) {
942
+ const innerRef = React8.useRef(null);
943
+ const ref = React8.useCallback((node) => {
944
+ innerRef.current = node;
945
+ if (typeof textAreaRef === "function") textAreaRef(node);
946
+ else if (textAreaRef) textAreaRef.current = node;
947
+ }, [textAreaRef]);
948
+ const grow = React8.useCallback(() => {
949
+ const el = innerRef.current;
950
+ if (!el || !autoGrow) return;
951
+ const styles = getComputedStyle(el);
952
+ const lineHeight = Number.parseFloat(styles.lineHeight) || Number.parseFloat(styles.fontSize) * 1.5;
953
+ const chrome = el.offsetHeight - el.clientHeight;
954
+ el.style.height = "auto";
955
+ const wanted = maxRows ? Math.min(el.scrollHeight, Math.ceil(lineHeight * maxRows)) : el.scrollHeight;
956
+ const next = `${wanted + chrome}px`;
957
+ if (el.style.height !== next) el.style.height = next;
958
+ }, [autoGrow, maxRows]);
959
+ useIsomorphicLayoutEffect(() => {
960
+ if (!autoGrow) {
961
+ if (innerRef.current) innerRef.current.style.height = "";
962
+ return;
963
+ }
964
+ grow();
965
+ }, [autoGrow, grow, rest.value]);
966
+ return /* @__PURE__ */ jsxs11(
967
+ TextField2,
968
+ {
969
+ className: cx("pire-field", className),
970
+ style,
971
+ onChange,
972
+ validationBehavior: "aria",
973
+ ...rest,
974
+ children: [
975
+ label ? /* @__PURE__ */ jsxs11(Label2, { className: "pire-field-label", children: [
976
+ label,
977
+ rest.isRequired ? /* @__PURE__ */ jsx18("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
978
+ ] }) : null,
979
+ /* @__PURE__ */ jsx18(
980
+ Group2,
981
+ {
982
+ className: "pire-control",
983
+ "data-size": size,
984
+ "data-full-width": String(fullWidth),
985
+ "data-multiline": "true",
986
+ "data-invalid": rest.isInvalid ? "true" : void 0,
987
+ "data-readonly": rest.isReadOnly ? "true" : void 0,
988
+ children: /* @__PURE__ */ jsx18(
989
+ AriaTextArea,
990
+ {
991
+ ref,
992
+ rows,
993
+ onInput: autoGrow ? grow : void 0,
994
+ className: cx("pire-input", "pire-textarea"),
995
+ "data-auto-grow": autoGrow ? "true" : void 0
996
+ }
997
+ )
998
+ }
999
+ ),
1000
+ description ? /* @__PURE__ */ jsx18(Text3, { slot: "description", className: "pire-field-hint", children: description }) : null,
1001
+ /* @__PURE__ */ jsx18(FieldError2, { className: "pire-field-error", children: errorMessage })
1002
+ ]
1003
+ }
1004
+ );
1005
+ }
1006
+
988
1007
  // src/components/forms/Select.tsx
1008
+ import {
1009
+ Select as AriaSelect,
1010
+ Label as Label3,
1011
+ Button as AriaButton5,
1012
+ SelectValue,
1013
+ Popover,
1014
+ ListBox,
1015
+ ListBoxItem,
1016
+ Text as Text4,
1017
+ FieldError as FieldError3
1018
+ } from "react-aria-components";
989
1019
  import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
990
1020
  var norm = (o) => typeof o === "string" ? { value: o, label: o, isDisabled: false } : o;
991
1021
  function Select({
@@ -1024,7 +1054,7 @@ function Select({
1024
1054
  rest.isRequired ? /* @__PURE__ */ jsx19("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1025
1055
  ] }) : null,
1026
1056
  /* @__PURE__ */ jsxs12(
1027
- AriaButton4,
1057
+ AriaButton5,
1028
1058
  {
1029
1059
  className: "pire-control",
1030
1060
  "data-size": size,
@@ -1107,7 +1137,7 @@ import {
1107
1137
  ComboBox as AriaComboBox,
1108
1138
  Label as Label5,
1109
1139
  Input as AriaInput2,
1110
- Button as AriaButton5,
1140
+ Button as AriaButton6,
1111
1141
  Group as Group3,
1112
1142
  Popover as Popover2,
1113
1143
  ListBox as ListBox2,
@@ -1175,7 +1205,7 @@ function ComboBox({
1175
1205
  children: [
1176
1206
  /* @__PURE__ */ jsx23(Icon, { name: "search", size: 16, className: "pire-leading-icon" }),
1177
1207
  /* @__PURE__ */ jsx23(AriaInput2, { className: "pire-input", placeholder: rest.placeholder }),
1178
- /* @__PURE__ */ jsx23(AriaButton5, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.comboBoxShowSuggestions, style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsx23(Icon, { name: "chevron-down", size: 16 }) })
1208
+ /* @__PURE__ */ jsx23(AriaButton6, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.comboBoxShowSuggestions, style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsx23(Icon, { name: "chevron-down", size: 16 }) })
1179
1209
  ]
1180
1210
  }
1181
1211
  ),
@@ -1202,12 +1232,12 @@ function ComboBox({
1202
1232
  }
1203
1233
 
1204
1234
  // src/components/forms/MultiComboBox.tsx
1205
- import * as React7 from "react";
1235
+ import * as React9 from "react";
1206
1236
  import {
1207
1237
  ComboBox as AriaComboBox2,
1208
1238
  Label as Label6,
1209
1239
  Input as AriaInput3,
1210
- Button as AriaButton6,
1240
+ Button as AriaButton7,
1211
1241
  ButtonContext,
1212
1242
  Group as Group4,
1213
1243
  Popover as Popover3,
@@ -1241,15 +1271,15 @@ function MultiComboBox({
1241
1271
  ...rest
1242
1272
  }) {
1243
1273
  const msg = usePireMessages();
1244
- const items = React7.useMemo(() => options.map(norm3), [options]);
1274
+ const items = React9.useMemo(() => options.map(norm3), [options]);
1245
1275
  const collection = isFilteredExternally ? { items } : { defaultItems: items };
1246
1276
  const showsStatus = isLoading || isFilteredExternally && items.length === 0 && emptyLabel != null;
1247
- const [uncontrolled, setUncontrolled] = React7.useState(defaultValue ?? []);
1248
- const [announcement, setAnnouncement] = React7.useState("");
1249
- const inputRef = React7.useRef(null);
1277
+ const [uncontrolled, setUncontrolled] = React9.useState(defaultValue ?? []);
1278
+ const [announcement, setAnnouncement] = React9.useState("");
1279
+ const inputRef = React9.useRef(null);
1250
1280
  const raw = value ?? uncontrolled;
1251
1281
  const contentKey = raw.join("\0");
1252
- const values = React7.useMemo(() => raw, [contentKey]);
1282
+ const values = React9.useMemo(() => raw, [contentKey]);
1253
1283
  const labelOf = (v) => items.find((o) => o.value === v)?.label ?? v;
1254
1284
  const isEditable = !rest.isDisabled && !rest.isReadOnly;
1255
1285
  const commit = (next) => {
@@ -1330,7 +1360,7 @@ function MultiComboBox({
1330
1360
  }
1331
1361
  )
1332
1362
  ] }),
1333
- /* @__PURE__ */ jsx24(AriaButton6, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.comboBoxShowSuggestions, style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsx24(Icon, { name: "chevron-down", size: 16 }) })
1363
+ /* @__PURE__ */ jsx24(AriaButton7, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.comboBoxShowSuggestions, style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsx24(Icon, { name: "chevron-down", size: 16 }) })
1334
1364
  ]
1335
1365
  }
1336
1366
  ),
@@ -1363,7 +1393,7 @@ import {
1363
1393
  Label as Label7,
1364
1394
  Input as AriaInput4,
1365
1395
  Group as Group5,
1366
- Button as AriaButton7,
1396
+ Button as AriaButton8,
1367
1397
  Text as Text8,
1368
1398
  FieldError as FieldError7
1369
1399
  } from "react-aria-components";
@@ -1398,8 +1428,8 @@ function NumberField({
1398
1428
  /* @__PURE__ */ jsx25(AriaInput4, { className: "pire-input", "data-numeric": "true" }),
1399
1429
  suffix ? /* @__PURE__ */ jsx25("span", { className: "pire-affix", children: suffix }) : null,
1400
1430
  hideStepper ? null : /* @__PURE__ */ jsxs18("span", { className: "pire-stepper", children: [
1401
- /* @__PURE__ */ jsx25(AriaButton7, { slot: "increment", className: "pire-stepper-btn", "aria-label": msg.numberFieldIncrease, children: /* @__PURE__ */ jsx25(Icon, { name: "plus", size: 10 }) }),
1402
- /* @__PURE__ */ jsx25(AriaButton7, { slot: "decrement", className: "pire-stepper-btn", "aria-label": msg.numberFieldDecrease, children: /* @__PURE__ */ jsx25(Icon, { name: "minus", size: 10 }) })
1431
+ /* @__PURE__ */ jsx25(AriaButton8, { slot: "increment", className: "pire-stepper-btn", "aria-label": msg.numberFieldIncrease, children: /* @__PURE__ */ jsx25(Icon, { name: "plus", size: 10 }) }),
1432
+ /* @__PURE__ */ jsx25(AriaButton8, { slot: "decrement", className: "pire-stepper-btn", "aria-label": msg.numberFieldDecrease, children: /* @__PURE__ */ jsx25(Icon, { name: "minus", size: 10 }) })
1403
1433
  ] })
1404
1434
  ]
1405
1435
  }
@@ -1416,7 +1446,7 @@ import {
1416
1446
  Group as Group6,
1417
1447
  DateInput,
1418
1448
  DateSegment,
1419
- Button as AriaButton8,
1449
+ Button as AriaButton9,
1420
1450
  Popover as Popover4,
1421
1451
  Dialog as AriaDialog,
1422
1452
  Calendar,
@@ -1456,7 +1486,7 @@ function DatePicker({
1456
1486
  "data-readonly": rest.isReadOnly ? "true" : void 0,
1457
1487
  children: [
1458
1488
  /* @__PURE__ */ jsx26(DateInput, { className: "pire-datefield", children: (segment) => /* @__PURE__ */ jsx26(DateSegment, { segment, className: "pire-datesegment" }) }),
1459
- /* @__PURE__ */ jsx26(AriaButton8, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerOpenCalendar, style: { width: 24, height: 24 }, children: /* @__PURE__ */ jsx26(Icon, { name: "calendar", size: 16 }) })
1489
+ /* @__PURE__ */ jsx26(AriaButton9, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerOpenCalendar, style: { width: 24, height: 24 }, children: /* @__PURE__ */ jsx26(Icon, { name: "calendar", size: 16 }) })
1460
1490
  ]
1461
1491
  }
1462
1492
  ),
@@ -1464,9 +1494,9 @@ function DatePicker({
1464
1494
  /* @__PURE__ */ jsx26(FieldError8, { className: "pire-field-error", children: errorMessage }),
1465
1495
  /* @__PURE__ */ jsx26(Popover4, { className: "pire-popover", children: /* @__PURE__ */ jsx26(AriaDialog, { children: /* @__PURE__ */ jsxs19(Calendar, { className: "pire-calendar", children: [
1466
1496
  /* @__PURE__ */ jsxs19("header", { className: "pire-calendar-head", children: [
1467
- /* @__PURE__ */ jsx26(AriaButton8, { slot: "previous", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerPreviousMonth, children: /* @__PURE__ */ jsx26(Icon, { name: "chevron-left", size: 16 }) }),
1497
+ /* @__PURE__ */ jsx26(AriaButton9, { slot: "previous", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerPreviousMonth, children: /* @__PURE__ */ jsx26(Icon, { name: "chevron-left", size: 16 }) }),
1468
1498
  /* @__PURE__ */ jsx26(Heading2, { className: "pire-calendar-title" }),
1469
- /* @__PURE__ */ jsx26(AriaButton8, { slot: "next", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerNextMonth, children: /* @__PURE__ */ jsx26(Icon, { name: "chevron-right", size: 16 }) })
1499
+ /* @__PURE__ */ jsx26(AriaButton9, { slot: "next", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerNextMonth, children: /* @__PURE__ */ jsx26(Icon, { name: "chevron-right", size: 16 }) })
1470
1500
  ] }),
1471
1501
  /* @__PURE__ */ jsxs19(CalendarGrid, { className: "pire-calendar-grid", children: [
1472
1502
  /* @__PURE__ */ jsx26(CalendarGridHeader, { children: (day) => /* @__PURE__ */ jsx26(CalendarHeaderCell, { children: day }) }),
@@ -1483,7 +1513,7 @@ import {
1483
1513
  Group as Group7,
1484
1514
  DateInput as DateInput2,
1485
1515
  DateSegment as DateSegment2,
1486
- Button as AriaButton9,
1516
+ Button as AriaButton10,
1487
1517
  Popover as Popover5,
1488
1518
  Dialog as AriaDialog2,
1489
1519
  RangeCalendar,
@@ -1545,7 +1575,7 @@ function DateRangePicker({
1545
1575
  /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", className: "pire-daterange-dash", children: "\u2013" }),
1546
1576
  /* @__PURE__ */ jsx27(DateInput2, { slot: "end", className: "pire-datefield", children: (segment) => /* @__PURE__ */ jsx27(DateSegment2, { segment, className: "pire-datesegment" }) }),
1547
1577
  /* @__PURE__ */ jsx27(
1548
- AriaButton9,
1578
+ AriaButton10,
1549
1579
  {
1550
1580
  className: "pire-iconbtn",
1551
1581
  "data-size": "sm",
@@ -1564,7 +1594,7 @@ function DateRangePicker({
1564
1594
  // Before the calendar in the DOM, so keyboard users reach the shortcut without
1565
1595
  // arrowing through a month first.
1566
1596
  /* @__PURE__ */ jsx27("div", { className: "pire-daterange-presets", role: "group", "aria-label": msg.dateRangePresetsLabel, children: presets.map((preset) => /* @__PURE__ */ jsx27(
1567
- AriaButton9,
1597
+ AriaButton10,
1568
1598
  {
1569
1599
  className: "pire-daterange-preset",
1570
1600
  onPress: () => rest.onChange?.(preset.range()),
@@ -1576,7 +1606,7 @@ function DateRangePicker({
1576
1606
  /* @__PURE__ */ jsxs20(RangeCalendar, { className: "pire-calendar", children: [
1577
1607
  /* @__PURE__ */ jsxs20("header", { className: "pire-calendar-head", children: [
1578
1608
  /* @__PURE__ */ jsx27(
1579
- AriaButton9,
1609
+ AriaButton10,
1580
1610
  {
1581
1611
  slot: "previous",
1582
1612
  className: "pire-iconbtn",
@@ -1587,7 +1617,7 @@ function DateRangePicker({
1587
1617
  ),
1588
1618
  /* @__PURE__ */ jsx27(Heading3, { className: "pire-calendar-title" }),
1589
1619
  /* @__PURE__ */ jsx27(
1590
- AriaButton9,
1620
+ AriaButton10,
1591
1621
  {
1592
1622
  slot: "next",
1593
1623
  className: "pire-iconbtn",
@@ -1609,14 +1639,27 @@ function DateRangePicker({
1609
1639
  }
1610
1640
 
1611
1641
  // src/components/forms/ValueHelpField.tsx
1612
- import * as React9 from "react";
1642
+ import * as React12 from "react";
1613
1643
 
1614
1644
  // src/components/patterns/ValueHelpDialog.tsx
1615
- import * as React8 from "react";
1645
+ import * as React11 from "react";
1616
1646
 
1617
1647
  // src/components/feedback/Dialog.tsx
1648
+ import * as React10 from "react";
1618
1649
  import { ModalOverlay, Modal, Dialog as AriaDialog3, Heading as Heading4 } from "react-aria-components";
1619
1650
  import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1651
+ function DialogTitle({ children, className }) {
1652
+ return /* @__PURE__ */ jsx28(Heading4, { slot: "title", className: cx("pire-dialog-title", className), children });
1653
+ }
1654
+ function DialogDescription({ children, className }) {
1655
+ return /* @__PURE__ */ jsx28("p", { className: cx("pire-dialog-sub", className), style: { margin: 0 }, children });
1656
+ }
1657
+ function DialogBody({ children, className }) {
1658
+ return /* @__PURE__ */ jsx28("div", { className: cx("pire-dialog-body", className), children });
1659
+ }
1660
+ function DialogActions({ children, className }) {
1661
+ return /* @__PURE__ */ jsx28("footer", { className: cx("pire-dialog-foot", className), children });
1662
+ }
1620
1663
  function Dialog({
1621
1664
  isOpen,
1622
1665
  onOpenChange,
@@ -1636,6 +1679,18 @@ function Dialog({
1636
1679
  onClose?.();
1637
1680
  onOpenChange?.(false);
1638
1681
  };
1682
+ const parts = React10.Children.toArray(children);
1683
+ const slotOf = (type) => parts.find((node) => React10.isValidElement(node) && node.type === type);
1684
+ const titleSlot = slotOf(DialogTitle);
1685
+ const descriptionSlot = slotOf(DialogDescription);
1686
+ const bodySlot = slotOf(DialogBody);
1687
+ const actionsSlot = slotOf(DialogActions);
1688
+ const slots = [titleSlot, descriptionSlot, bodySlot, actionsSlot];
1689
+ const loose = parts.filter((node) => !slots.includes(node));
1690
+ const heading = titleSlot ?? (title ? /* @__PURE__ */ jsx28(Heading4, { slot: "title", className: "pire-dialog-title", children: title }) : null);
1691
+ const description = descriptionSlot ?? (subtitle ? /* @__PURE__ */ jsx28("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null);
1692
+ const actions = actionsSlot ?? (footer ? /* @__PURE__ */ jsx28("footer", { className: "pire-dialog-foot", children: footer }) : null);
1693
+ const body = bodySlot ?? (loose.length ? /* @__PURE__ */ jsx28("div", { className: "pire-dialog-body", children: loose }) : null);
1639
1694
  return /* @__PURE__ */ jsx28(
1640
1695
  ModalOverlay,
1641
1696
  {
@@ -1646,15 +1701,15 @@ function Dialog({
1646
1701
  if (!o) close();
1647
1702
  },
1648
1703
  children: /* @__PURE__ */ jsx28(Modal, { className: cx("pire-modal", className), "data-size": size, style, children: /* @__PURE__ */ jsxs21(AriaDialog3, { className: "pire-dialog", children: [
1649
- title ? /* @__PURE__ */ jsxs21("header", { className: "pire-dialog-head", children: [
1704
+ heading || description ? /* @__PURE__ */ jsxs21("header", { className: "pire-dialog-head", children: [
1650
1705
  /* @__PURE__ */ jsxs21("div", { style: { flex: 1, minWidth: 0 }, children: [
1651
- /* @__PURE__ */ jsx28(Heading4, { slot: "title", className: "pire-dialog-title", children: title }),
1652
- subtitle ? /* @__PURE__ */ jsx28("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
1706
+ heading,
1707
+ description
1653
1708
  ] }),
1654
1709
  showClose ? /* @__PURE__ */ jsx28(IconButton, { icon: "x", label: msg.dialogClose, size: "sm", onPress: close }) : null
1655
1710
  ] }) : null,
1656
- children ? /* @__PURE__ */ jsx28("div", { className: "pire-dialog-body", children }) : null,
1657
- footer ? /* @__PURE__ */ jsx28("footer", { className: "pire-dialog-foot", children: footer }) : null
1711
+ body,
1712
+ actions
1658
1713
  ] }) })
1659
1714
  }
1660
1715
  );
@@ -1665,6 +1720,7 @@ import {
1665
1720
  Table,
1666
1721
  TableHeader,
1667
1722
  TableBody,
1723
+ TableFooter,
1668
1724
  Column,
1669
1725
  Row,
1670
1726
  Cell
@@ -1732,6 +1788,10 @@ function DataTable({
1732
1788
  isLoading,
1733
1789
  loadingRowCount,
1734
1790
  loadingLabel,
1791
+ footer,
1792
+ rowProps,
1793
+ renderExpanded,
1794
+ expandedIds,
1735
1795
  className,
1736
1796
  style,
1737
1797
  ...rest
@@ -1748,6 +1808,11 @@ function DataTable({
1748
1808
  ...columns.map((c) => ({ width: c.width, align: c.align, numeric: c.numeric }))
1749
1809
  ];
1750
1810
  const body = isLoading ? [] : rows;
1811
+ const presentation = new Map(rows.map((row) => [row.id, rowProps?.(row) ?? {}]));
1812
+ const disabledKeys = rows.filter((row) => presentation.get(row.id)?.isDisabled).map((row) => row.id);
1813
+ const expanded = new Set((expandedIds ?? []).map(String));
1814
+ const spanAll = columns.length + (selectable ? 1 : 0);
1815
+ const expandedKey = (id) => `${id}::__pire_expanded__`;
1751
1816
  return /* @__PURE__ */ jsx30(
1752
1817
  "div",
1753
1818
  {
@@ -1762,6 +1827,7 @@ function DataTable({
1762
1827
  "data-density": density,
1763
1828
  "data-sticky": String(stickyHeader),
1764
1829
  "aria-label": rest["aria-label"],
1830
+ disabledKeys: disabledKeys.length ? new Set(disabledKeys) : void 0,
1765
1831
  selectionMode: selectable ? "multiple" : "none",
1766
1832
  selectedKeys: selected ? new Set(selected) : void 0,
1767
1833
  onSelectionChange: handleSelection,
@@ -1784,7 +1850,7 @@ function DataTable({
1784
1850
  width: c.width,
1785
1851
  "data-align": c.numeric || c.align === "right" ? "right" : c.align,
1786
1852
  "data-allows-sorting": c.sortable ? "true" : void 0,
1787
- children: /* @__PURE__ */ jsxs22("span", { className: "pire-th-inner", children: [
1853
+ children: /* @__PURE__ */ jsxs22("span", { className: cx("pire-th-inner", c.hideLabel && "pire-sr-only"), children: [
1788
1854
  c.label,
1789
1855
  c.sortable ? /* @__PURE__ */ jsx30(
1790
1856
  Icon,
@@ -1805,19 +1871,46 @@ function DataTable({
1805
1871
  // biome-ignore lint/suspicious/noArrayIndexKey: placeholder rows are positional.
1806
1872
  /* @__PURE__ */ jsx30(SkeletonTableRow, { columns: skeletonColumns, density }, i)
1807
1873
  ))
1808
- ] }) : /* @__PURE__ */ jsx30("div", { className: "pire-table-empty", children: emptyLabel }), children: body.map((row) => /* @__PURE__ */ jsxs22(Row, { id: row.id, className: "pire-tr", "data-pressable": onRowAction ? "true" : void 0, children: [
1809
- selectable ? /* @__PURE__ */ jsx30(Cell, { className: "pire-td", children: /* @__PURE__ */ jsx30(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectRow }) }) : null,
1810
- columns.map((c) => /* @__PURE__ */ jsx30(
1874
+ ] }) : /* @__PURE__ */ jsx30("div", { className: "pire-table-empty", children: emptyLabel }), children: body.flatMap((row) => {
1875
+ const rowIsDisabled = presentation.get(row.id)?.isDisabled;
1876
+ const record = /* @__PURE__ */ jsxs22(
1877
+ Row,
1878
+ {
1879
+ id: row.id,
1880
+ className: cx("pire-tr", presentation.get(row.id)?.className),
1881
+ "data-pressable": onRowAction && !rowIsDisabled ? "true" : void 0,
1882
+ children: [
1883
+ selectable ? /* @__PURE__ */ jsx30(Cell, { className: "pire-td", children: /* @__PURE__ */ jsx30(Checkbox, { slot: "selection", "aria-label": msg.dataTableSelectRow }) }) : null,
1884
+ columns.map((c) => /* @__PURE__ */ jsx30(
1885
+ Cell,
1886
+ {
1887
+ className: "pire-td",
1888
+ "data-numeric": c.numeric ? "true" : void 0,
1889
+ style: { textAlign: c.align && !c.numeric ? c.align : void 0 },
1890
+ children: c.render ? c.render(row) : row[c.key]
1891
+ },
1892
+ c.key
1893
+ ))
1894
+ ]
1895
+ },
1896
+ row.id
1897
+ );
1898
+ if (!renderExpanded || !expanded.has(String(row.id))) return [record];
1899
+ return [record, /* @__PURE__ */ jsx30(Row, { id: expandedKey(row.id), className: "pire-tr-expanded", children: /* @__PURE__ */ jsx30(Cell, { className: "pire-td-expanded", colSpan: spanAll, children: renderExpanded(row) }) }, expandedKey(row.id))];
1900
+ }) }),
1901
+ footer && !isLoading ? /* @__PURE__ */ jsx30(TableFooter, { className: "pire-tfoot", children: /* @__PURE__ */ jsxs22(Row, { id: "__pire_footer__", className: "pire-tr-footer", children: [
1902
+ selectable ? /* @__PURE__ */ jsx30(Cell, { className: "pire-tf" }) : null,
1903
+ columns.map((c, i) => /* @__PURE__ */ jsx30(
1811
1904
  Cell,
1812
1905
  {
1813
- className: "pire-td",
1906
+ className: "pire-tf",
1814
1907
  "data-numeric": c.numeric ? "true" : void 0,
1815
1908
  style: { textAlign: c.align && !c.numeric ? c.align : void 0 },
1816
- children: c.render ? c.render(row) : row[c.key]
1909
+ children: footer[c.key] ?? (i === 0 && !selectable ? /* @__PURE__ */ jsx30("span", { className: "pire-sr-only", children: msg.dataTableSummaryRow }) : null)
1817
1910
  },
1818
1911
  c.key
1819
1912
  ))
1820
- ] }, row.id)) })
1913
+ ] }) }) : null
1821
1914
  ]
1822
1915
  }
1823
1916
  )
@@ -1842,11 +1935,11 @@ function ValueHelpDialog({
1842
1935
  onClose
1843
1936
  }) {
1844
1937
  const msg = usePireMessages();
1845
- const [query, setQuery] = React8.useState("");
1846
- React8.useEffect(() => {
1938
+ const [query, setQuery] = React11.useState("");
1939
+ React11.useEffect(() => {
1847
1940
  if (isOpen) setQuery("");
1848
1941
  }, [isOpen]);
1849
- const filtered = React8.useMemo(() => {
1942
+ const filtered = React11.useMemo(() => {
1850
1943
  if (isFilteredExternally) return rows;
1851
1944
  const q = query.trim().toLowerCase();
1852
1945
  if (!q) return rows;
@@ -1873,6 +1966,7 @@ function ValueHelpDialog({
1873
1966
  type: "search",
1874
1967
  value: query,
1875
1968
  onChange: handleSearch,
1969
+ isClearable: true,
1876
1970
  placeholder: searchPlaceholder ?? msg.valueHelpDialogSearchPlaceholder,
1877
1971
  autoFocus: true
1878
1972
  }
@@ -1927,7 +2021,7 @@ function ValueHelpField({
1927
2021
  style
1928
2022
  }) {
1929
2023
  const msg = usePireMessages();
1930
- const [open, setOpen] = React9.useState(false);
2024
+ const [open, setOpen] = React12.useState(false);
1931
2025
  return /* @__PURE__ */ jsxs24("div", { className: cx(className), style, children: [
1932
2026
  /* @__PURE__ */ jsx32(
1933
2027
  Input,
@@ -1983,7 +2077,7 @@ function ValueHelpField({
1983
2077
  }
1984
2078
 
1985
2079
  // src/components/forms/FileUpload.tsx
1986
- import * as React10 from "react";
2080
+ import * as React13 from "react";
1987
2081
  import { FileTrigger, Text as Text11 } from "react-aria-components";
1988
2082
 
1989
2083
  // src/components/feedback/ProgressBar.tsx
@@ -2073,10 +2167,10 @@ function FileUpload({
2073
2167
  style
2074
2168
  }) {
2075
2169
  const msg = usePireMessages();
2076
- const [uncontrolled, setUncontrolled] = React10.useState(defaultValue ?? []);
2170
+ const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
2077
2171
  const files = value ?? uncontrolled;
2078
- const created = React10.useRef([]);
2079
- React10.useEffect(() => () => {
2172
+ const created = React13.useRef([]);
2173
+ React13.useEffect(() => () => {
2080
2174
  for (const url of created.current) URL.revokeObjectURL(url);
2081
2175
  }, []);
2082
2176
  const commit = (next) => {
@@ -2140,7 +2234,7 @@ function FileUpload({
2140
2234
  }
2141
2235
 
2142
2236
  // src/components/navigation/ShellBar.tsx
2143
- import { MenuTrigger, Button as AriaButton10, Popover as Popover6 } from "react-aria-components";
2237
+ import { MenuTrigger, Button as AriaButton11, Popover as Popover6 } from "react-aria-components";
2144
2238
  import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
2145
2239
  var initials2 = (name) => name.trim().split(/\s+/).slice(0, 2).map((p) => p[0]).join("").toUpperCase();
2146
2240
  function ShellBar({
@@ -2173,7 +2267,7 @@ function ShellBar({
2173
2267
  // rendered here rather than expected from the consumer so the panel keeps shell placement.
2174
2268
  /* @__PURE__ */ jsxs27(MenuTrigger, { children: [
2175
2269
  /* @__PURE__ */ jsx35(
2176
- AriaButton10,
2270
+ AriaButton11,
2177
2271
  {
2178
2272
  className: "pire-avatar pire-avatar-trigger",
2179
2273
  "aria-label": (userMenuLabel ?? msg.shellBarUserMenu).replace("{user}", user),
@@ -2187,9 +2281,9 @@ function ShellBar({
2187
2281
  }
2188
2282
 
2189
2283
  // src/components/navigation/SideNav.tsx
2190
- import * as React11 from "react";
2284
+ import * as React14 from "react";
2191
2285
  import {
2192
- Button as AriaButton11,
2286
+ Button as AriaButton12,
2193
2287
  Disclosure,
2194
2288
  DisclosureGroup,
2195
2289
  DisclosurePanel,
@@ -2287,10 +2381,10 @@ function SideNav({
2287
2381
  const msg = usePireMessages();
2288
2382
  const activeParent = findActiveParent(groups, value);
2289
2383
  const isControlled = expandedIds != null;
2290
- const [ownExpanded, setOwnExpanded] = React11.useState(
2384
+ const [ownExpanded, setOwnExpanded] = React14.useState(
2291
2385
  () => new Set(defaultExpandedIds ?? (activeParent ? [activeParent] : []))
2292
2386
  );
2293
- const [lastValue, setLastValue] = React11.useState(value);
2387
+ const [lastValue, setLastValue] = React14.useState(value);
2294
2388
  if (value !== lastValue) {
2295
2389
  setLastValue(value);
2296
2390
  if (!isControlled && activeParent && !ownExpanded.has(activeParent)) {
@@ -2311,7 +2405,7 @@ function SideNav({
2311
2405
  const renderRow = (item, onPress, isGroup) => {
2312
2406
  const selected = !isGroup && item.id === value;
2313
2407
  const button = /* @__PURE__ */ jsxs29(
2314
- AriaButton11,
2408
+ AriaButton12,
2315
2409
  {
2316
2410
  className: "pire-sidenav-item",
2317
2411
  "data-selected": selected ? "true" : void 0,
@@ -2331,7 +2425,7 @@ function SideNav({
2331
2425
  };
2332
2426
  const renderRailFlyout = (item) => /* @__PURE__ */ jsxs29(MenuTrigger2, { children: [
2333
2427
  /* @__PURE__ */ jsx37(
2334
- AriaButton11,
2428
+ AriaButton12,
2335
2429
  {
2336
2430
  className: "pire-sidenav-item",
2337
2431
  "aria-label": item.label,
@@ -2351,7 +2445,7 @@ function SideNav({
2351
2445
  ] }, item.id);
2352
2446
  const renderSection = (item) => /* @__PURE__ */ jsxs29(Disclosure, { id: item.id, className: "pire-sidenav-section", children: [
2353
2447
  /* @__PURE__ */ jsxs29(
2354
- AriaButton11,
2448
+ AriaButton12,
2355
2449
  {
2356
2450
  slot: "trigger",
2357
2451
  className: "pire-sidenav-item",
@@ -2368,7 +2462,7 @@ function SideNav({
2368
2462
  /* @__PURE__ */ jsx37(DisclosurePanel, { className: "pire-sidenav-subnav", children: item.items?.map((child) => {
2369
2463
  const selected = child.id === value;
2370
2464
  return /* @__PURE__ */ jsxs29(
2371
- AriaButton11,
2465
+ AriaButton12,
2372
2466
  {
2373
2467
  className: "pire-sidenav-item pire-sidenav-subitem",
2374
2468
  "data-selected": selected ? "true" : void 0,
@@ -2554,7 +2648,7 @@ function InlineMessage({ kind = "info", title, action, onClose, children, classN
2554
2648
  }
2555
2649
 
2556
2650
  // src/components/feedback/Toast.tsx
2557
- import * as React12 from "react";
2651
+ import * as React15 from "react";
2558
2652
  import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
2559
2653
  var KIND_ICON2 = {
2560
2654
  info: "info",
@@ -2580,32 +2674,32 @@ function Toast({ kind = "success", onClose, position = "bottom-center", children
2580
2674
  }
2581
2675
  );
2582
2676
  }
2583
- var ToastContext = React12.createContext(null);
2677
+ var ToastContext = React15.createContext(null);
2584
2678
  function ToastProvider({ children, timeout = 6e3 }) {
2585
2679
  const msg = usePireMessages();
2586
- const [toasts, setToasts] = React12.useState([]);
2587
- const close = React12.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
2588
- const add = React12.useCallback((toast) => {
2680
+ const [toasts, setToasts] = React15.useState([]);
2681
+ const close = React15.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
2682
+ const add = React15.useCallback((toast) => {
2589
2683
  const id = Math.random().toString(36).slice(2);
2590
2684
  setToasts((t) => [...t, { ...toast, id }]);
2591
2685
  const ms = toast.timeout ?? timeout;
2592
2686
  if (ms > 0) setTimeout(() => close(id), ms);
2593
2687
  return id;
2594
2688
  }, [close, timeout]);
2595
- const value = React12.useMemo(() => ({ add, close }), [add, close]);
2689
+ const value = React15.useMemo(() => ({ add, close }), [add, close]);
2596
2690
  return /* @__PURE__ */ jsxs34(ToastContext.Provider, { value, children: [
2597
2691
  children,
2598
2692
  /* @__PURE__ */ jsx42("div", { className: "pire-toast-region", role: "region", "aria-label": msg.toastRegionLabel, children: toasts.map((t) => /* @__PURE__ */ jsx42(Toast, { kind: t.kind, onClose: () => close(t.id), style: { position: "static", transform: "none" }, children: t.message }, t.id)) })
2599
2693
  ] });
2600
2694
  }
2601
2695
  function useToast() {
2602
- const ctx = React12.useContext(ToastContext);
2696
+ const ctx = React15.useContext(ToastContext);
2603
2697
  if (!ctx) throw new Error("useToast must be used inside <ToastProvider>");
2604
2698
  return ctx;
2605
2699
  }
2606
2700
 
2607
2701
  // src/components/data/KpiTile.tsx
2608
- import { Button as AriaButton12 } from "react-aria-components";
2702
+ import { Button as AriaButton13 } from "react-aria-components";
2609
2703
  import { Fragment as Fragment3, jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
2610
2704
  function KpiTile({
2611
2705
  label,
@@ -2638,7 +2732,7 @@ function KpiTile({
2638
2732
  footnote ? /* @__PURE__ */ jsx43("span", { className: "pire-kpi-foot", children: footnote }) : null
2639
2733
  ] });
2640
2734
  const props = { className: cx("pire-kpi", className), "data-status": status, style };
2641
- return onPress ? /* @__PURE__ */ jsx43(AriaButton12, { ...props, "data-pressable": "true", onPress, children: body }) : /* @__PURE__ */ jsx43("div", { ...props, children: body });
2735
+ return onPress ? /* @__PURE__ */ jsx43(AriaButton13, { ...props, "data-pressable": "true", onPress, children: body }) : /* @__PURE__ */ jsx43("div", { ...props, children: body });
2642
2736
  }
2643
2737
 
2644
2738
  // src/components/data/ObjectHeader.tsx
@@ -2949,14 +3043,14 @@ function BarChart({
2949
3043
  }
2950
3044
 
2951
3045
  // src/components/data/LineChart.tsx
2952
- import * as React13 from "react";
3046
+ import * as React16 from "react";
2953
3047
  import { jsx as jsx50, jsxs as jsxs42 } from "react/jsx-runtime";
2954
3048
  var PLOT_INSET = { top: 10, right: 14, bottom: 24, left: 58 };
2955
3049
  var MARKER_LIMIT = 20;
2956
- var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React13.useEffect : React13.useLayoutEffect;
3050
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React16.useEffect : React16.useLayoutEffect;
2957
3051
  function useMeasuredWidth() {
2958
- const ref = React13.useRef(null);
2959
- const [width, setWidth] = React13.useState(0);
3052
+ const ref = React16.useRef(null);
3053
+ const [width, setWidth] = React16.useState(0);
2960
3054
  useIsomorphicLayoutEffect2(() => {
2961
3055
  const element = ref.current;
2962
3056
  if (!element) return;
@@ -3119,7 +3213,7 @@ function LineChart({
3119
3213
  }
3120
3214
 
3121
3215
  // src/components/data/DonutChart.tsx
3122
- import * as React14 from "react";
3216
+ import * as React17 from "react";
3123
3217
  import { jsx as jsx51, jsxs as jsxs43 } from "react/jsx-runtime";
3124
3218
  var SEGMENT_GAP_DEGREES = 1.5;
3125
3219
  function DonutChart({
@@ -3140,7 +3234,7 @@ function DonutChart({
3140
3234
  }) {
3141
3235
  const label = rest["aria-label"];
3142
3236
  const msg = usePireMessages();
3143
- const [hoveredIndex, setHoveredIndex] = React14.useState(null);
3237
+ const [hoveredIndex, setHoveredIndex] = React17.useState(null);
3144
3238
  warnOnDonutShape(series, categories.length, label);
3145
3239
  const values = (series[0]?.values ?? []).slice(0, categories.length);
3146
3240
  const segments = categories.map((category, index) => ({ category, index, value: values[index] ?? 0 })).filter((segment) => segment.value > 0);
@@ -3218,14 +3312,14 @@ function colorForSegment(index) {
3218
3312
  }
3219
3313
 
3220
3314
  // src/components/data/LinkList.tsx
3221
- import { Button as AriaButton13 } from "react-aria-components";
3315
+ import { Button as AriaButton14 } from "react-aria-components";
3222
3316
  import { jsx as jsx52, jsxs as jsxs44 } from "react/jsx-runtime";
3223
3317
  function LinkList({ items, onSelect, emphasis = "key", className, ...rest }) {
3224
3318
  return /* @__PURE__ */ jsx52("div", { className: cx("pire-linklist", className), role: "list", "data-emphasis": emphasis, ...rest, children: items.map((item) => {
3225
3319
  const keySlot = item.key ? /* @__PURE__ */ jsx52("span", { className: "pire-linklist-key", children: item.key }) : null;
3226
3320
  const textSlot = item.text ? /* @__PURE__ */ jsx52("span", { className: "pire-linklist-text", children: item.text }) : null;
3227
3321
  const [first, second] = emphasis === "text" ? [textSlot, keySlot] : [keySlot, textSlot];
3228
- return /* @__PURE__ */ jsx52("div", { role: "listitem", className: "pire-linklist-row", children: /* @__PURE__ */ jsxs44(AriaButton13, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
3322
+ return /* @__PURE__ */ jsx52("div", { role: "listitem", className: "pire-linklist-row", children: /* @__PURE__ */ jsxs44(AriaButton14, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
3229
3323
  item.icon ? /* @__PURE__ */ jsx52(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
3230
3324
  first,
3231
3325
  second,
@@ -3342,7 +3436,7 @@ function ConfirmDialog({
3342
3436
  }
3343
3437
 
3344
3438
  // src/components/patterns/CommandPalette.tsx
3345
- import * as React15 from "react";
3439
+ import * as React18 from "react";
3346
3440
  import {
3347
3441
  Autocomplete,
3348
3442
  ModalOverlay as ModalOverlay2,
@@ -3376,17 +3470,17 @@ function CommandPalette({
3376
3470
  style
3377
3471
  }) {
3378
3472
  const msg = usePireMessages();
3379
- const [query, setQuery] = React15.useState("");
3473
+ const [query, setQuery] = React18.useState("");
3380
3474
  const { contains } = useFilter({ sensitivity: "base" });
3381
- React15.useEffect(() => {
3475
+ React18.useEffect(() => {
3382
3476
  if (isOpen) setQuery("");
3383
3477
  }, [isOpen]);
3384
- const searchableById = React15.useMemo(() => {
3478
+ const searchableById = React18.useMemo(() => {
3385
3479
  const byId = /* @__PURE__ */ new Map();
3386
3480
  for (const group of groups) for (const item of group.items) byId.set(item.id, searchableText(item));
3387
3481
  return byId;
3388
3482
  }, [groups]);
3389
- const filter = React15.useCallback((textValue, inputValue, node) => {
3483
+ const filter = React18.useCallback((textValue, inputValue, node) => {
3390
3484
  if (node.parentKey === RESULTS_SECTION_KEY) return true;
3391
3485
  return contains(searchableById.get(String(node.key)) ?? textValue, inputValue);
3392
3486
  }, [contains, searchableById]);
@@ -3469,9 +3563,9 @@ function CommandPalette({
3469
3563
  );
3470
3564
  }
3471
3565
  function useCommandPaletteShortcut(onTrigger, { key = "k", isDisabled } = {}) {
3472
- const handler = React15.useRef(onTrigger);
3566
+ const handler = React18.useRef(onTrigger);
3473
3567
  handler.current = onTrigger;
3474
- React15.useEffect(() => {
3568
+ React18.useEffect(() => {
3475
3569
  if (isDisabled) return;
3476
3570
  const onKeyDown = (event) => {
3477
3571
  if (!(event.metaKey || event.ctrlKey) || event.altKey) return;
@@ -3525,7 +3619,7 @@ function EmptyState({ icon = "file-text", title, action, compact, children, clas
3525
3619
  }
3526
3620
 
3527
3621
  // src/components/patterns/FileDropZone.tsx
3528
- import * as React16 from "react";
3622
+ import * as React19 from "react";
3529
3623
  import { DropZone, FileTrigger as FileTrigger2, isFileDropItem } from "react-aria-components";
3530
3624
  import { jsx as jsx62, jsxs as jsxs53 } from "react/jsx-runtime";
3531
3625
  var isImage2 = (file) => file.type.startsWith("image/");
@@ -3553,10 +3647,10 @@ function FileDropZone({
3553
3647
  style
3554
3648
  }) {
3555
3649
  const msg = usePireMessages();
3556
- const [uncontrolled, setUncontrolled] = React16.useState(defaultValue ?? []);
3650
+ const [uncontrolled, setUncontrolled] = React19.useState(defaultValue ?? []);
3557
3651
  const files = value ?? uncontrolled;
3558
- const created = React16.useRef([]);
3559
- React16.useEffect(() => () => {
3652
+ const created = React19.useRef([]);
3653
+ React19.useEffect(() => () => {
3560
3654
  for (const url of created.current) URL.revokeObjectURL(url);
3561
3655
  }, []);
3562
3656
  const commit = (next) => {
@@ -3630,6 +3724,7 @@ function FileDropZone({
3630
3724
 
3631
3725
  // src/index.ts
3632
3726
  import { DialogTrigger, MenuTrigger as MenuTrigger3, SubmenuTrigger, Popover as Popover8, RouterProvider, I18nProvider } from "react-aria-components";
3727
+ import { Focusable as Focusable2 } from "react-aria-components";
3633
3728
  export {
3634
3729
  Avatar,
3635
3730
  Badge,
@@ -3646,12 +3741,17 @@ export {
3646
3741
  DateRangePicker,
3647
3742
  DescriptionList,
3648
3743
  Dialog,
3744
+ DialogActions,
3745
+ DialogBody,
3746
+ DialogDescription,
3747
+ DialogTitle,
3649
3748
  DialogTrigger,
3650
3749
  DonutChart,
3651
3750
  EmptyState,
3652
3751
  FileDropZone,
3653
3752
  FileUpload,
3654
3753
  FilterBar,
3754
+ Focusable2 as Focusable,
3655
3755
  FooterBar,
3656
3756
  FormField,
3657
3757
  Heading,