@orianatech/pire 0.7.0 → 0.9.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
@@ -813,6 +813,7 @@ var enMessages = {
813
813
  toastDismiss: "Dismiss",
814
814
  toastRegionLabel: "Notifications",
815
815
  comboBoxShowSuggestions: "Show suggestions",
816
+ comboBoxLoading: "Searching\u2026",
816
817
  datePickerOpenCalendar: "Open calendar",
817
818
  datePickerPreviousMonth: "Previous month",
818
819
  datePickerNextMonth: "Next month",
@@ -829,7 +830,11 @@ var enMessages = {
829
830
  paginationPrevious: "Previous page",
830
831
  paginationNext: "Next page",
831
832
  paginationRowsPerPage: "Rows per page",
832
- sideNavLabel: "Main navigation"
833
+ sideNavLabel: "Main navigation",
834
+ fileUploadChoose: "Choose files",
835
+ fileUploadRemoveNamed: "Remove {name}",
836
+ fileUploadUploading: "Uploading",
837
+ fileDropZonePrompt: "Drag files here, or choose them"
833
838
  };
834
839
  var esMessages = {
835
840
  filterBarLabel: "Filtros",
@@ -844,6 +849,7 @@ var esMessages = {
844
849
  toastDismiss: "Descartar",
845
850
  toastRegionLabel: "Notificaciones",
846
851
  comboBoxShowSuggestions: "Mostrar sugerencias",
852
+ comboBoxLoading: "Buscando\u2026",
847
853
  datePickerOpenCalendar: "Abrir calendario",
848
854
  datePickerPreviousMonth: "Mes anterior",
849
855
  datePickerNextMonth: "Mes siguiente",
@@ -860,7 +866,11 @@ var esMessages = {
860
866
  paginationPrevious: "P\xE1gina anterior",
861
867
  paginationNext: "P\xE1gina siguiente",
862
868
  paginationRowsPerPage: "Filas por p\xE1gina",
863
- sideNavLabel: "Navegaci\xF3n principal"
869
+ sideNavLabel: "Navegaci\xF3n principal",
870
+ fileUploadChoose: "Elegir archivos",
871
+ fileUploadRemoveNamed: "Quitar {name}",
872
+ fileUploadUploading: "Subiendo",
873
+ fileDropZonePrompt: "Arrastr\xE1 archivos ac\xE1, o elegilos"
864
874
  };
865
875
 
866
876
  // src/i18n/PireIntlProvider.tsx
@@ -895,12 +905,19 @@ function ComboBox({
895
905
  errorMessage,
896
906
  size = "md",
897
907
  fullWidth = true,
908
+ isFilteredExternally,
909
+ isLoading,
910
+ loadingLabel,
911
+ emptyLabel,
912
+ onLoadMore,
898
913
  className,
899
914
  style,
900
915
  ...rest
901
916
  }) {
902
917
  const msg = usePireMessages();
903
918
  const items = options.map(norm2);
919
+ const collection = isFilteredExternally ? { items } : { defaultItems: items };
920
+ const showsStatus = isLoading || isFilteredExternally && items.length === 0 && emptyLabel != null;
904
921
  return /* @__PURE__ */ jsxs16(
905
922
  AriaComboBox,
906
923
  {
@@ -908,9 +925,13 @@ function ComboBox({
908
925
  style,
909
926
  selectedKey: value,
910
927
  defaultSelectedKey: defaultValue,
911
- onSelectionChange: (k) => onChange?.(k == null ? null : String(k)),
928
+ onSelectionChange: (k) => {
929
+ if (isLoading) return;
930
+ onChange?.(k == null ? null : String(k));
931
+ },
912
932
  onInputChange,
913
- defaultItems: items,
933
+ ...collection,
934
+ allowsEmptyCollection: isFilteredExternally || isLoading,
914
935
  menuTrigger: "input",
915
936
  validationBehavior: "aria",
916
937
  ...rest,
@@ -935,10 +956,21 @@ function ComboBox({
935
956
  ),
936
957
  description ? /* @__PURE__ */ jsx22(Text6, { slot: "description", className: "pire-field-hint", children: description }) : null,
937
958
  /* @__PURE__ */ jsx22(FieldError5, { className: "pire-field-error", children: errorMessage }),
938
- /* @__PURE__ */ jsx22(Popover2, { className: "pire-popover", children: /* @__PURE__ */ jsx22(ListBox2, { className: "pire-listbox", children: (item) => /* @__PURE__ */ jsxs16(ListBoxItem2, { className: "pire-option", id: item.value, textValue: item.label, isDisabled: item.isDisabled, children: [
939
- /* @__PURE__ */ jsx22("span", { style: { flex: 1 }, children: item.label }),
940
- item.secondary ? /* @__PURE__ */ jsx22("span", { style: { font: "var(--type-code)", color: "var(--text-tertiary)" }, children: item.secondary }) : null
941
- ] }) }) })
959
+ /* @__PURE__ */ jsx22(Popover2, { className: "pire-popover", children: /* @__PURE__ */ jsx22(
960
+ ListBox2,
961
+ {
962
+ className: "pire-listbox",
963
+ onScroll: onLoadMore ? (e) => {
964
+ const el = e.currentTarget;
965
+ if (el.scrollHeight - el.scrollTop - el.clientHeight < 48) onLoadMore();
966
+ } : void 0,
967
+ renderEmptyState: showsStatus ? () => /* @__PURE__ */ jsx22("div", { className: "pire-listbox-status", role: "status", "aria-live": "polite", children: isLoading ? loadingLabel ?? msg.comboBoxLoading : emptyLabel }) : void 0,
968
+ children: (item) => /* @__PURE__ */ jsxs16(ListBoxItem2, { className: "pire-option", id: item.value, textValue: item.label, isDisabled: item.isDisabled, children: [
969
+ /* @__PURE__ */ jsx22("span", { className: "pire-option-label", children: item.label }),
970
+ item.secondary ? /* @__PURE__ */ jsx22("span", { className: "pire-option-secondary", children: item.secondary }) : null
971
+ ] })
972
+ }
973
+ ) })
942
974
  ]
943
975
  }
944
976
  );
@@ -973,6 +1005,11 @@ function MultiComboBox({
973
1005
  errorMessage,
974
1006
  allowsCustomValue,
975
1007
  size = "md",
1008
+ isFilteredExternally,
1009
+ isLoading,
1010
+ loadingLabel,
1011
+ emptyLabel,
1012
+ onLoadMore,
976
1013
  fullWidth = true,
977
1014
  className,
978
1015
  style,
@@ -980,6 +1017,8 @@ function MultiComboBox({
980
1017
  }) {
981
1018
  const msg = usePireMessages();
982
1019
  const items = React7.useMemo(() => options.map(norm3), [options]);
1020
+ const collection = isFilteredExternally ? { items } : { defaultItems: items };
1021
+ const showsStatus = isLoading || isFilteredExternally && items.length === 0 && emptyLabel != null;
983
1022
  const [uncontrolled, setUncontrolled] = React7.useState(defaultValue ?? []);
984
1023
  const [announcement, setAnnouncement] = React7.useState("");
985
1024
  const inputRef = React7.useRef(null);
@@ -1025,9 +1064,12 @@ function MultiComboBox({
1025
1064
  style,
1026
1065
  selectionMode: "multiple",
1027
1066
  value: values,
1028
- onChange: (keys) => commit(keys.map(String)),
1067
+ onChange: (keys) => {
1068
+ if (!isLoading) commit(keys.map(String));
1069
+ },
1029
1070
  onInputChange,
1030
- defaultItems: items,
1071
+ ...collection,
1072
+ allowsEmptyCollection: isFilteredExternally || isLoading,
1031
1073
  menuTrigger: "input",
1032
1074
  validationBehavior: "aria",
1033
1075
  ...rest,
@@ -1070,10 +1112,21 @@ function MultiComboBox({
1070
1112
  /* @__PURE__ */ jsx23(VisuallyHidden, { children: /* @__PURE__ */ jsx23("span", { "aria-live": "polite", children: announcement }) }),
1071
1113
  description ? /* @__PURE__ */ jsx23(Text7, { slot: "description", className: "pire-field-hint", children: description }) : null,
1072
1114
  /* @__PURE__ */ jsx23(FieldError6, { className: "pire-field-error", children: errorMessage }),
1073
- /* @__PURE__ */ jsx23(Popover3, { className: "pire-popover", children: /* @__PURE__ */ jsx23(ListBox3, { className: "pire-listbox", children: (item) => /* @__PURE__ */ jsxs17(ListBoxItem3, { className: "pire-option", id: item.value, textValue: item.label, isDisabled: item.isDisabled, children: [
1074
- /* @__PURE__ */ jsx23("span", { style: { flex: 1 }, children: item.label }),
1075
- item.secondary ? /* @__PURE__ */ jsx23("span", { style: { font: "var(--type-code)", color: "var(--text-tertiary)" }, children: item.secondary }) : null
1076
- ] }) }) })
1115
+ /* @__PURE__ */ jsx23(Popover3, { className: "pire-popover", children: /* @__PURE__ */ jsx23(
1116
+ ListBox3,
1117
+ {
1118
+ className: "pire-listbox",
1119
+ onScroll: onLoadMore ? (e) => {
1120
+ const el = e.currentTarget;
1121
+ if (el.scrollHeight - el.scrollTop - el.clientHeight < 48) onLoadMore();
1122
+ } : void 0,
1123
+ renderEmptyState: showsStatus ? () => /* @__PURE__ */ jsx23("div", { className: "pire-listbox-status", role: "status", "aria-live": "polite", children: isLoading ? loadingLabel ?? msg.comboBoxLoading : emptyLabel }) : void 0,
1124
+ children: (item) => /* @__PURE__ */ jsxs17(ListBoxItem3, { className: "pire-option", id: item.value, textValue: item.label, isDisabled: item.isDisabled, children: [
1125
+ /* @__PURE__ */ jsx23("span", { className: "pire-option-label", children: item.label }),
1126
+ item.secondary ? /* @__PURE__ */ jsx23("span", { className: "pire-option-secondary", children: item.secondary }) : null
1127
+ ] })
1128
+ }
1129
+ ) })
1077
1130
  ]
1078
1131
  }
1079
1132
  );
@@ -1551,8 +1604,165 @@ function ValueHelpField({
1551
1604
  ] });
1552
1605
  }
1553
1606
 
1607
+ // src/components/forms/FileUpload.tsx
1608
+ import * as React10 from "react";
1609
+ import { FileTrigger, Text as Text10 } from "react-aria-components";
1610
+
1611
+ // src/components/feedback/ProgressBar.tsx
1612
+ import { ProgressBar as AriaProgressBar, Label as Label9 } from "react-aria-components";
1613
+ import { Fragment as Fragment2, jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
1614
+ function ProgressBar({
1615
+ value = 0,
1616
+ minValue = 0,
1617
+ maxValue = 100,
1618
+ label,
1619
+ showValue = true,
1620
+ isIndeterminate,
1621
+ status = "informative",
1622
+ size = "md",
1623
+ className,
1624
+ style
1625
+ }) {
1626
+ return /* @__PURE__ */ jsx31(
1627
+ AriaProgressBar,
1628
+ {
1629
+ className: cx("pire-progress", className),
1630
+ "data-status": status,
1631
+ "data-size": size,
1632
+ value,
1633
+ minValue,
1634
+ maxValue,
1635
+ isIndeterminate,
1636
+ style,
1637
+ children: ({ percentage, valueText }) => /* @__PURE__ */ jsxs24(Fragment2, { children: [
1638
+ label || showValue ? /* @__PURE__ */ jsxs24("div", { className: "pire-progress-head", children: [
1639
+ label ? /* @__PURE__ */ jsx31(Label9, { children: label }) : /* @__PURE__ */ jsx31("span", {}),
1640
+ showValue && !isIndeterminate ? /* @__PURE__ */ jsx31("span", { className: "pire-numeric", children: valueText }) : null
1641
+ ] }) : null,
1642
+ /* @__PURE__ */ jsx31("div", { className: "pire-progress-track", children: /* @__PURE__ */ jsx31("div", { className: "pire-progress-fill", style: { width: `${isIndeterminate ? 40 : percentage}%` } }) })
1643
+ ] })
1644
+ }
1645
+ );
1646
+ }
1647
+
1648
+ // src/components/forms/FileUpload.tsx
1649
+ import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
1650
+ var isImage = (file) => file.type.startsWith("image/");
1651
+ function formatFileSize(bytes) {
1652
+ if (bytes < 1024) return `${bytes} B`;
1653
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024).toLocaleString()} KB`;
1654
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1655
+ }
1656
+ function screenFiles(files, { maxSize, acceptedFileTypes }) {
1657
+ const accepted = [];
1658
+ const rejected = [];
1659
+ for (const file of files) {
1660
+ if (maxSize != null && file.size > maxSize) {
1661
+ rejected.push({ file, reason: "size" });
1662
+ continue;
1663
+ }
1664
+ if (acceptedFileTypes?.length) {
1665
+ const ok = acceptedFileTypes.some((t) => t.startsWith(".") ? file.name.toLowerCase().endsWith(t.toLowerCase()) : t.endsWith("/*") ? file.type.startsWith(t.slice(0, -1)) : file.type === t);
1666
+ if (!ok) {
1667
+ rejected.push({ file, reason: "type" });
1668
+ continue;
1669
+ }
1670
+ }
1671
+ accepted.push(file);
1672
+ }
1673
+ return { accepted, rejected };
1674
+ }
1675
+ function FileUpload({
1676
+ label,
1677
+ value,
1678
+ defaultValue,
1679
+ onChange,
1680
+ acceptedFileTypes,
1681
+ allowsMultiple,
1682
+ maxSize,
1683
+ onError,
1684
+ showPreview = true,
1685
+ uploadProgress,
1686
+ chooseLabel,
1687
+ description,
1688
+ errorMessage,
1689
+ isInvalid,
1690
+ isDisabled,
1691
+ isReadOnly,
1692
+ isRequired,
1693
+ fullWidth = true,
1694
+ className,
1695
+ style
1696
+ }) {
1697
+ const msg = usePireMessages();
1698
+ const [uncontrolled, setUncontrolled] = React10.useState(defaultValue ?? []);
1699
+ const files = value ?? uncontrolled;
1700
+ const created = React10.useRef([]);
1701
+ React10.useEffect(() => () => {
1702
+ for (const url of created.current) URL.revokeObjectURL(url);
1703
+ }, []);
1704
+ const commit = (next) => {
1705
+ if (value === void 0) setUncontrolled(next);
1706
+ onChange?.(next);
1707
+ };
1708
+ const accept = (picked) => {
1709
+ if (!picked || isDisabled || isReadOnly) return;
1710
+ const { accepted, rejected } = screenFiles([...picked], { maxSize, acceptedFileTypes });
1711
+ if (rejected.length) onError?.(rejected);
1712
+ if (!accepted.length) return;
1713
+ const wrapped = accepted.map((file) => {
1714
+ const previewUrl = showPreview && isImage(file) ? URL.createObjectURL(file) : void 0;
1715
+ if (previewUrl) created.current.push(previewUrl);
1716
+ return { file, previewUrl };
1717
+ });
1718
+ commit(allowsMultiple ? [...files, ...wrapped] : wrapped.slice(0, 1));
1719
+ };
1720
+ const remove = (target) => commit(files.filter((f) => f.file !== target));
1721
+ return /* @__PURE__ */ jsxs25(
1722
+ "div",
1723
+ {
1724
+ className: cx("pire-field", "pire-fileupload", className),
1725
+ style,
1726
+ "data-full-width": String(fullWidth),
1727
+ "data-invalid": isInvalid ? "true" : void 0,
1728
+ children: [
1729
+ label ? /* @__PURE__ */ jsxs25("span", { className: "pire-field-label", children: [
1730
+ label,
1731
+ isRequired ? /* @__PURE__ */ jsx32("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1732
+ ] }) : null,
1733
+ /* @__PURE__ */ jsx32(
1734
+ FileTrigger,
1735
+ {
1736
+ acceptedFileTypes,
1737
+ allowsMultiple,
1738
+ onSelect: accept,
1739
+ children: /* @__PURE__ */ jsx32(Button, { icon: "paperclip", isDisabled: isDisabled || isReadOnly, children: chooseLabel ?? msg.fileUploadChoose })
1740
+ }
1741
+ ),
1742
+ files.length ? /* @__PURE__ */ jsx32("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ jsxs25("li", { className: "pire-fileupload-item", children: [
1743
+ previewUrl ? /* @__PURE__ */ jsx32("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ jsx32(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
1744
+ /* @__PURE__ */ jsx32("span", { className: "pire-fileupload-name", children: file.name }),
1745
+ /* @__PURE__ */ jsx32("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
1746
+ isDisabled || isReadOnly ? null : /* @__PURE__ */ jsx32(
1747
+ IconButton,
1748
+ {
1749
+ icon: "x",
1750
+ size: "sm",
1751
+ label: msg.fileUploadRemoveNamed.replace("{name}", file.name),
1752
+ onPress: () => remove(file)
1753
+ }
1754
+ )
1755
+ ] }, `${file.name}-${file.size}-${file.lastModified}`)) }) : null,
1756
+ uploadProgress != null ? /* @__PURE__ */ jsx32(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
1757
+ description ? /* @__PURE__ */ jsx32(Text10, { slot: "description", className: "pire-field-hint", children: description }) : null,
1758
+ isInvalid && errorMessage ? /* @__PURE__ */ jsx32("span", { className: "pire-field-error", children: errorMessage }) : null
1759
+ ]
1760
+ }
1761
+ );
1762
+ }
1763
+
1554
1764
  // src/components/navigation/ShellBar.tsx
1555
- import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
1765
+ import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
1556
1766
  var initials2 = (name) => name.trim().split(/\s+/).slice(0, 2).map((p) => p[0]).join("").toUpperCase();
1557
1767
  function ShellBar({
1558
1768
  product,
@@ -1567,22 +1777,88 @@ function ShellBar({
1567
1777
  className,
1568
1778
  ...rest
1569
1779
  }) {
1570
- return /* @__PURE__ */ jsxs24("header", { className: cx("pire-shellbar", className), ...rest, children: [
1571
- onMenu ? /* @__PURE__ */ jsx31(IconButton, { icon: "menu", label: menuLabel, variant: "inverse", size: "sm", onPress: onMenu }) : null,
1572
- monogram ? /* @__PURE__ */ jsx31("span", { className: "pire-shellbar-mono", "aria-hidden": "true", children: monogram }) : null,
1573
- product ? /* @__PURE__ */ jsx31("span", { className: "pire-shellbar-product", children: product }) : null,
1574
- title ? /* @__PURE__ */ jsx31("span", { className: "pire-shellbar-title", children: title }) : null,
1575
- /* @__PURE__ */ jsx31("span", { className: "pire-shellbar-spacer" }),
1576
- onSearch ? /* @__PURE__ */ jsx31(IconButton, { icon: "search", label: searchLabel, variant: "inverse", size: "sm", onPress: onSearch }) : null,
1780
+ return /* @__PURE__ */ jsxs26("header", { className: cx("pire-shellbar", className), ...rest, children: [
1781
+ onMenu ? /* @__PURE__ */ jsx33(IconButton, { icon: "menu", label: menuLabel, variant: "inverse", size: "sm", onPress: onMenu }) : null,
1782
+ monogram ? /* @__PURE__ */ jsx33("span", { className: "pire-shellbar-mono", "aria-hidden": "true", children: monogram }) : null,
1783
+ product ? /* @__PURE__ */ jsx33("span", { className: "pire-shellbar-product", children: product }) : null,
1784
+ title ? /* @__PURE__ */ jsx33("span", { className: "pire-shellbar-title", children: title }) : null,
1785
+ /* @__PURE__ */ jsx33("span", { className: "pire-shellbar-spacer" }),
1786
+ onSearch ? /* @__PURE__ */ jsx33(IconButton, { icon: "search", label: searchLabel, variant: "inverse", size: "sm", onPress: onSearch }) : null,
1577
1787
  actions,
1578
- user ? /* @__PURE__ */ jsx31("span", { className: "pire-avatar", title: user, "aria-label": user, role: "img", children: initials2(user) }) : null
1788
+ user ? /* @__PURE__ */ jsx33("span", { className: "pire-avatar", title: user, "aria-label": user, role: "img", children: initials2(user) }) : null
1579
1789
  ] });
1580
1790
  }
1581
1791
 
1582
1792
  // src/components/navigation/SideNav.tsx
1583
- import * as React10 from "react";
1584
- import { Button as AriaButton9, Disclosure, DisclosureGroup, DisclosurePanel } from "react-aria-components";
1585
- import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
1793
+ import * as React11 from "react";
1794
+ import {
1795
+ Button as AriaButton9,
1796
+ Disclosure,
1797
+ DisclosureGroup,
1798
+ DisclosurePanel,
1799
+ MenuTrigger,
1800
+ Popover as Popover5
1801
+ } from "react-aria-components";
1802
+
1803
+ // src/components/navigation/Menu.tsx
1804
+ import {
1805
+ Menu as AriaMenu,
1806
+ MenuItem as AriaMenuItem,
1807
+ MenuSection as AriaMenuSection,
1808
+ Separator as AriaSeparator2,
1809
+ Header
1810
+ } from "react-aria-components";
1811
+ import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
1812
+ function Menu({ minWidth, className, style, ...rest }) {
1813
+ const width = typeof minWidth === "number" ? `${minWidth}px` : minWidth;
1814
+ const menuStyle = width == null ? style : { ["--pire-menu-min-w"]: width, ...style };
1815
+ return /* @__PURE__ */ jsx34(
1816
+ AriaMenu,
1817
+ {
1818
+ className: cx("pire-menu", className),
1819
+ style: menuStyle,
1820
+ ...rest
1821
+ }
1822
+ );
1823
+ }
1824
+ function MenuItem({
1825
+ children,
1826
+ icon,
1827
+ description,
1828
+ shortcut,
1829
+ tone = "default",
1830
+ className,
1831
+ ...rest
1832
+ }) {
1833
+ return /* @__PURE__ */ jsxs27(
1834
+ AriaMenuItem,
1835
+ {
1836
+ className: cx("pire-menu-item", className),
1837
+ "data-tone": tone === "danger" ? "danger" : void 0,
1838
+ ...rest,
1839
+ children: [
1840
+ icon ? /* @__PURE__ */ jsx34(Icon, { name: icon, size: 16, className: "pire-menu-item-icon" }) : null,
1841
+ /* @__PURE__ */ jsxs27("span", { className: "pire-menu-item-body", children: [
1842
+ /* @__PURE__ */ jsx34("span", { className: "pire-menu-item-label", children }),
1843
+ description ? /* @__PURE__ */ jsx34("span", { className: "pire-menu-item-desc", children: description }) : null
1844
+ ] }),
1845
+ shortcut ? /* @__PURE__ */ jsx34("kbd", { className: "pire-menu-item-shortcut", children: shortcut }) : null
1846
+ ]
1847
+ }
1848
+ );
1849
+ }
1850
+ function MenuSection({ title, children, className, ...rest }) {
1851
+ return /* @__PURE__ */ jsxs27(AriaMenuSection, { className: cx("pire-menu-section", className), ...rest, children: [
1852
+ title ? /* @__PURE__ */ jsx34(Header, { className: "pire-menu-section-title", children: title }) : null,
1853
+ children
1854
+ ] });
1855
+ }
1856
+ function MenuSeparator({ className }) {
1857
+ return /* @__PURE__ */ jsx34(AriaSeparator2, { className: cx("pire-menu-separator", className) });
1858
+ }
1859
+
1860
+ // src/components/navigation/SideNav.tsx
1861
+ import { jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
1586
1862
  function findActiveParent(groups, value) {
1587
1863
  if (value == null) return void 0;
1588
1864
  for (const group of groups) {
@@ -1600,6 +1876,7 @@ function SideNav({
1600
1876
  defaultExpandedIds,
1601
1877
  onExpandedChange,
1602
1878
  collapsed,
1879
+ railFlyout = true,
1603
1880
  footer,
1604
1881
  className,
1605
1882
  ...rest
@@ -1607,10 +1884,10 @@ function SideNav({
1607
1884
  const msg = usePireMessages();
1608
1885
  const activeParent = findActiveParent(groups, value);
1609
1886
  const isControlled = expandedIds != null;
1610
- const [ownExpanded, setOwnExpanded] = React10.useState(
1887
+ const [ownExpanded, setOwnExpanded] = React11.useState(
1611
1888
  () => new Set(defaultExpandedIds ?? (activeParent ? [activeParent] : []))
1612
1889
  );
1613
- const [lastValue, setLastValue] = React10.useState(value);
1890
+ const [lastValue, setLastValue] = React11.useState(value);
1614
1891
  if (value !== lastValue) {
1615
1892
  setLastValue(value);
1616
1893
  if (!isControlled && activeParent && !ownExpanded.has(activeParent)) {
@@ -1630,7 +1907,7 @@ function SideNav({
1630
1907
  };
1631
1908
  const renderRow = (item, onPress, isGroup) => {
1632
1909
  const selected = !isGroup && item.id === value;
1633
- const button = /* @__PURE__ */ jsxs25(
1910
+ const button = /* @__PURE__ */ jsxs28(
1634
1911
  AriaButton9,
1635
1912
  {
1636
1913
  className: "pire-sidenav-item",
@@ -1640,17 +1917,37 @@ function SideNav({
1640
1917
  "aria-label": collapsed ? item.label : void 0,
1641
1918
  onPress,
1642
1919
  children: [
1643
- item.icon ? /* @__PURE__ */ jsx32(Icon, { name: item.icon, size: 16 }) : null,
1644
- collapsed ? null : /* @__PURE__ */ jsx32("span", { children: item.label }),
1645
- item.count != null && !collapsed ? /* @__PURE__ */ jsx32("span", { className: "pire-sidenav-count", children: item.count }) : null
1920
+ item.icon ? /* @__PURE__ */ jsx35(Icon, { name: item.icon, size: 16 }) : null,
1921
+ collapsed ? null : /* @__PURE__ */ jsx35("span", { children: item.label }),
1922
+ item.count != null && !collapsed ? /* @__PURE__ */ jsx35("span", { className: "pire-sidenav-count", children: item.count }) : null
1646
1923
  ]
1647
1924
  },
1648
1925
  item.id
1649
1926
  );
1650
- return collapsed ? /* @__PURE__ */ jsx32(Tooltip, { label: item.label, placement: "right", children: button }, item.id) : button;
1927
+ return collapsed ? /* @__PURE__ */ jsx35(Tooltip, { label: item.label, placement: "right", children: button }, item.id) : button;
1651
1928
  };
1652
- const renderSection = (item) => /* @__PURE__ */ jsxs25(Disclosure, { id: item.id, className: "pire-sidenav-section", children: [
1653
- /* @__PURE__ */ jsxs25(
1929
+ const renderRailFlyout = (item) => /* @__PURE__ */ jsxs28(MenuTrigger, { children: [
1930
+ /* @__PURE__ */ jsx35(
1931
+ AriaButton9,
1932
+ {
1933
+ className: "pire-sidenav-item",
1934
+ "aria-label": item.label,
1935
+ "data-active-child": item.id === activeParent ? "true" : void 0,
1936
+ children: item.icon ? /* @__PURE__ */ jsx35(Icon, { name: item.icon, size: 16 }) : null
1937
+ }
1938
+ ),
1939
+ /* @__PURE__ */ jsx35(Popover5, { className: "pire-popover", placement: "right top", offset: 4, children: /* @__PURE__ */ jsx35(
1940
+ Menu,
1941
+ {
1942
+ "aria-label": item.label,
1943
+ className: "pire-sidenav-flyout",
1944
+ onAction: (key) => onChange?.(String(key)),
1945
+ children: (item.items ?? []).map((child) => /* @__PURE__ */ jsx35(MenuItem, { id: child.id, children: child.label }, child.id))
1946
+ }
1947
+ ) })
1948
+ ] }, item.id);
1949
+ const renderSection = (item) => /* @__PURE__ */ jsxs28(Disclosure, { id: item.id, className: "pire-sidenav-section", children: [
1950
+ /* @__PURE__ */ jsxs28(
1654
1951
  AriaButton9,
1655
1952
  {
1656
1953
  slot: "trigger",
@@ -1658,16 +1955,16 @@ function SideNav({
1658
1955
  "data-kind": "group",
1659
1956
  "data-active-child": item.id === activeParent ? "true" : void 0,
1660
1957
  children: [
1661
- item.icon ? /* @__PURE__ */ jsx32(Icon, { name: item.icon, size: 16 }) : null,
1662
- /* @__PURE__ */ jsx32("span", { children: item.label }),
1663
- item.count != null ? /* @__PURE__ */ jsx32("span", { className: "pire-sidenav-count", children: item.count }) : null,
1664
- /* @__PURE__ */ jsx32(Icon, { name: "chevron-down", size: 16, className: "pire-sidenav-chevron" })
1958
+ item.icon ? /* @__PURE__ */ jsx35(Icon, { name: item.icon, size: 16 }) : null,
1959
+ /* @__PURE__ */ jsx35("span", { children: item.label }),
1960
+ item.count != null ? /* @__PURE__ */ jsx35("span", { className: "pire-sidenav-count", children: item.count }) : null,
1961
+ /* @__PURE__ */ jsx35(Icon, { name: "chevron-down", size: 16, className: "pire-sidenav-chevron" })
1665
1962
  ]
1666
1963
  }
1667
1964
  ),
1668
- /* @__PURE__ */ jsx32(DisclosurePanel, { className: "pire-sidenav-subnav", children: item.items?.map((child) => {
1965
+ /* @__PURE__ */ jsx35(DisclosurePanel, { className: "pire-sidenav-subnav", children: item.items?.map((child) => {
1669
1966
  const selected = child.id === value;
1670
- return /* @__PURE__ */ jsxs25(
1967
+ return /* @__PURE__ */ jsxs28(
1671
1968
  AriaButton9,
1672
1969
  {
1673
1970
  className: "pire-sidenav-item pire-sidenav-subitem",
@@ -1675,15 +1972,15 @@ function SideNav({
1675
1972
  "aria-current": selected ? "page" : void 0,
1676
1973
  onPress: () => onChange?.(child.id),
1677
1974
  children: [
1678
- /* @__PURE__ */ jsx32("span", { children: child.label }),
1679
- child.count != null ? /* @__PURE__ */ jsx32("span", { className: "pire-sidenav-count", children: child.count }) : null
1975
+ /* @__PURE__ */ jsx35("span", { children: child.label }),
1976
+ child.count != null ? /* @__PURE__ */ jsx35("span", { className: "pire-sidenav-count", children: child.count }) : null
1680
1977
  ]
1681
1978
  },
1682
1979
  child.id
1683
1980
  );
1684
1981
  }) })
1685
1982
  ] }, item.id);
1686
- return /* @__PURE__ */ jsxs25(
1983
+ return /* @__PURE__ */ jsxs28(
1687
1984
  "nav",
1688
1985
  {
1689
1986
  className: cx("pire-sidenav", className),
@@ -1696,11 +1993,12 @@ function SideNav({
1696
1993
  const rows = group.items.map((item) => {
1697
1994
  const isGroup = Boolean(item.items?.length);
1698
1995
  if (isGroup && !collapsed) return renderSection(item);
1996
+ if (isGroup && collapsed && railFlyout) return renderRailFlyout(item);
1699
1997
  return renderRow(item, () => isGroup ? toggleExpanded(item.id) : onChange?.(item.id), isGroup);
1700
1998
  });
1701
- return /* @__PURE__ */ jsxs25("div", { className: "pire-sidenav-group", children: [
1702
- group.label && !collapsed ? /* @__PURE__ */ jsx32("div", { className: "pire-sidenav-label", children: group.label }) : null,
1703
- hasSections ? /* @__PURE__ */ jsx32(
1999
+ return /* @__PURE__ */ jsxs28("div", { className: "pire-sidenav-group", children: [
2000
+ group.label && !collapsed ? /* @__PURE__ */ jsx35("div", { className: "pire-sidenav-label", children: group.label }) : null,
2001
+ hasSections ? /* @__PURE__ */ jsx35(
1704
2002
  DisclosureGroup,
1705
2003
  {
1706
2004
  className: "pire-sidenav-tree",
@@ -1712,7 +2010,7 @@ function SideNav({
1712
2010
  ) : rows
1713
2011
  ] }, group.label ?? gi);
1714
2012
  }),
1715
- footer ? /* @__PURE__ */ jsx32("div", { className: "pire-sidenav-footer", children: footer }) : null
2013
+ footer ? /* @__PURE__ */ jsx35("div", { className: "pire-sidenav-footer", children: footer }) : null
1716
2014
  ]
1717
2015
  }
1718
2016
  );
@@ -1720,9 +2018,9 @@ function SideNav({
1720
2018
 
1721
2019
  // src/components/navigation/Tabs.tsx
1722
2020
  import { Tabs as AriaTabs, TabList, Tab as AriaTab, TabPanel } from "react-aria-components";
1723
- import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
2021
+ import { jsx as jsx36, jsxs as jsxs29 } from "react/jsx-runtime";
1724
2022
  function Tabs({ items, value, defaultValue, onChange, panels, className, style, ...rest }) {
1725
- return /* @__PURE__ */ jsxs26(
2023
+ return /* @__PURE__ */ jsxs29(
1726
2024
  AriaTabs,
1727
2025
  {
1728
2026
  className,
@@ -1731,12 +2029,12 @@ function Tabs({ items, value, defaultValue, onChange, panels, className, style,
1731
2029
  defaultSelectedKey: defaultValue,
1732
2030
  onSelectionChange: (k) => onChange?.(String(k)),
1733
2031
  children: [
1734
- /* @__PURE__ */ jsx33(TabList, { className: "pire-tablist", items, "aria-label": rest["aria-label"] ?? "Views", children: (item) => /* @__PURE__ */ jsxs26(AriaTab, { className: cx("pire-tab"), id: item.id, isDisabled: item.isDisabled, children: [
1735
- item.icon ? /* @__PURE__ */ jsx33(Icon, { name: item.icon, size: 16 }) : null,
2032
+ /* @__PURE__ */ jsx36(TabList, { className: "pire-tablist", items, "aria-label": rest["aria-label"] ?? "Views", children: (item) => /* @__PURE__ */ jsxs29(AriaTab, { className: cx("pire-tab"), id: item.id, isDisabled: item.isDisabled, children: [
2033
+ item.icon ? /* @__PURE__ */ jsx36(Icon, { name: item.icon, size: 16 }) : null,
1736
2034
  item.label,
1737
- item.count != null ? /* @__PURE__ */ jsx33("span", { className: "pire-tab-count", children: item.count }) : null
2035
+ item.count != null ? /* @__PURE__ */ jsx36("span", { className: "pire-tab-count", children: item.count }) : null
1738
2036
  ] }) }),
1739
- items.map((item) => /* @__PURE__ */ jsx33(TabPanel, { id: item.id, className: panels ? "pire-tabpanel" : void 0, children: panels?.[item.id] }, item.id))
2037
+ items.map((item) => /* @__PURE__ */ jsx36(TabPanel, { id: item.id, className: panels ? "pire-tabpanel" : void 0, children: panels?.[item.id] }, item.id))
1740
2038
  ]
1741
2039
  }
1742
2040
  );
@@ -1744,9 +2042,9 @@ function Tabs({ items, value, defaultValue, onChange, panels, className, style,
1744
2042
 
1745
2043
  // src/components/navigation/Breadcrumb.tsx
1746
2044
  import { Breadcrumbs as AriaBreadcrumbs, Breadcrumb as AriaBreadcrumb, Link as Link2 } from "react-aria-components";
1747
- import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
2045
+ import { jsx as jsx37, jsxs as jsxs30 } from "react/jsx-runtime";
1748
2046
  function Breadcrumb({ items, onNavigate, className, style }) {
1749
- return /* @__PURE__ */ jsx34(
2047
+ return /* @__PURE__ */ jsx37(
1750
2048
  AriaBreadcrumbs,
1751
2049
  {
1752
2050
  className: cx("pire-breadcrumbs", className),
@@ -1755,9 +2053,9 @@ function Breadcrumb({ items, onNavigate, className, style }) {
1755
2053
  onAction: (key) => onNavigate?.(String(key)),
1756
2054
  children: (item) => {
1757
2055
  const last = items[items.length - 1] === item;
1758
- return /* @__PURE__ */ jsxs27(AriaBreadcrumb, { className: "pire-breadcrumb", id: item.id ?? item.label, children: [
1759
- last ? item.label : /* @__PURE__ */ jsx34(Link2, { href: item.href, children: item.label }),
1760
- last ? null : /* @__PURE__ */ jsx34(Icon, { name: "chevron-right", size: 12, style: { color: "var(--text-tertiary)" } })
2056
+ return /* @__PURE__ */ jsxs30(AriaBreadcrumb, { className: "pire-breadcrumb", id: item.id ?? item.label, children: [
2057
+ last ? item.label : /* @__PURE__ */ jsx37(Link2, { href: item.href, children: item.label }),
2058
+ last ? null : /* @__PURE__ */ jsx37(Icon, { name: "chevron-right", size: 12, style: { color: "var(--text-tertiary)" } })
1761
2059
  ] });
1762
2060
  }
1763
2061
  }
@@ -1765,7 +2063,7 @@ function Breadcrumb({ items, onNavigate, className, style }) {
1765
2063
  }
1766
2064
 
1767
2065
  // src/components/navigation/Pagination.tsx
1768
- import { jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
2066
+ import { jsx as jsx38, jsxs as jsxs31 } from "react/jsx-runtime";
1769
2067
  function Pagination({
1770
2068
  page = 1,
1771
2069
  pageSize = 25,
@@ -1780,9 +2078,9 @@ function Pagination({
1780
2078
  const pages = Math.max(1, Math.ceil(total / pageSize));
1781
2079
  const from = total === 0 ? 0 : (page - 1) * pageSize + 1;
1782
2080
  const to = Math.min(total, page * pageSize);
1783
- return /* @__PURE__ */ jsxs28("nav", { className: cx("pire-pagination", className), style, "aria-label": msg.paginationLabel, children: [
1784
- /* @__PURE__ */ jsx35("span", { className: "pire-pagination-count", children: msg.paginationRange.replace("{from}", from.toLocaleString()).replace("{to}", to.toLocaleString()).replace("{total}", total.toLocaleString()) }),
1785
- /* @__PURE__ */ jsx35(
2081
+ return /* @__PURE__ */ jsxs31("nav", { className: cx("pire-pagination", className), style, "aria-label": msg.paginationLabel, children: [
2082
+ /* @__PURE__ */ jsx38("span", { className: "pire-pagination-count", children: msg.paginationRange.replace("{from}", from.toLocaleString()).replace("{to}", to.toLocaleString()).replace("{total}", total.toLocaleString()) }),
2083
+ /* @__PURE__ */ jsx38(
1786
2084
  IconButton,
1787
2085
  {
1788
2086
  icon: "chevron-left",
@@ -1793,8 +2091,8 @@ function Pagination({
1793
2091
  onPress: () => onPageChange?.(page - 1)
1794
2092
  }
1795
2093
  ),
1796
- /* @__PURE__ */ jsx35("span", { className: "pire-pagination-count", "aria-live": "polite", children: msg.paginationPageOf.replace("{page}", String(page)).replace("{pages}", String(pages)) }),
1797
- /* @__PURE__ */ jsx35(
2094
+ /* @__PURE__ */ jsx38("span", { className: "pire-pagination-count", "aria-live": "polite", children: msg.paginationPageOf.replace("{page}", String(page)).replace("{pages}", String(pages)) }),
2095
+ /* @__PURE__ */ jsx38(
1798
2096
  IconButton,
1799
2097
  {
1800
2098
  icon: "chevron-right",
@@ -1805,7 +2103,7 @@ function Pagination({
1805
2103
  onPress: () => onPageChange?.(page + 1)
1806
2104
  }
1807
2105
  ),
1808
- onPageSizeChange ? /* @__PURE__ */ jsx35(
2106
+ onPageSizeChange ? /* @__PURE__ */ jsx38(
1809
2107
  Select,
1810
2108
  {
1811
2109
  "aria-label": msg.paginationRowsPerPage,
@@ -1820,65 +2118,8 @@ function Pagination({
1820
2118
  ] });
1821
2119
  }
1822
2120
 
1823
- // src/components/navigation/Menu.tsx
1824
- import {
1825
- Menu as AriaMenu,
1826
- MenuItem as AriaMenuItem,
1827
- MenuSection as AriaMenuSection,
1828
- Separator as AriaSeparator2,
1829
- Header
1830
- } from "react-aria-components";
1831
- import { jsx as jsx36, jsxs as jsxs29 } from "react/jsx-runtime";
1832
- function Menu({ minWidth, className, style, ...rest }) {
1833
- const width = typeof minWidth === "number" ? `${minWidth}px` : minWidth;
1834
- const menuStyle = width == null ? style : { ["--pire-menu-min-w"]: width, ...style };
1835
- return /* @__PURE__ */ jsx36(
1836
- AriaMenu,
1837
- {
1838
- className: cx("pire-menu", className),
1839
- style: menuStyle,
1840
- ...rest
1841
- }
1842
- );
1843
- }
1844
- function MenuItem({
1845
- children,
1846
- icon,
1847
- description,
1848
- shortcut,
1849
- tone = "default",
1850
- className,
1851
- ...rest
1852
- }) {
1853
- return /* @__PURE__ */ jsxs29(
1854
- AriaMenuItem,
1855
- {
1856
- className: cx("pire-menu-item", className),
1857
- "data-tone": tone === "danger" ? "danger" : void 0,
1858
- ...rest,
1859
- children: [
1860
- icon ? /* @__PURE__ */ jsx36(Icon, { name: icon, size: 16, className: "pire-menu-item-icon" }) : null,
1861
- /* @__PURE__ */ jsxs29("span", { className: "pire-menu-item-body", children: [
1862
- /* @__PURE__ */ jsx36("span", { className: "pire-menu-item-label", children }),
1863
- description ? /* @__PURE__ */ jsx36("span", { className: "pire-menu-item-desc", children: description }) : null
1864
- ] }),
1865
- shortcut ? /* @__PURE__ */ jsx36("kbd", { className: "pire-menu-item-shortcut", children: shortcut }) : null
1866
- ]
1867
- }
1868
- );
1869
- }
1870
- function MenuSection({ title, children, className, ...rest }) {
1871
- return /* @__PURE__ */ jsxs29(AriaMenuSection, { className: cx("pire-menu-section", className), ...rest, children: [
1872
- title ? /* @__PURE__ */ jsx36(Header, { className: "pire-menu-section-title", children: title }) : null,
1873
- children
1874
- ] });
1875
- }
1876
- function MenuSeparator({ className }) {
1877
- return /* @__PURE__ */ jsx36(AriaSeparator2, { className: cx("pire-menu-separator", className) });
1878
- }
1879
-
1880
2121
  // src/components/feedback/InlineMessage.tsx
1881
- import { jsx as jsx37, jsxs as jsxs30 } from "react/jsx-runtime";
2122
+ import { jsx as jsx39, jsxs as jsxs32 } from "react/jsx-runtime";
1882
2123
  var KIND_ICON = {
1883
2124
  info: "info",
1884
2125
  success: "check-circle-2",
@@ -1888,7 +2129,7 @@ var KIND_ICON = {
1888
2129
  function InlineMessage({ kind = "info", title, action, onClose, children, className, ...rest }) {
1889
2130
  const msg = usePireMessages();
1890
2131
  const assertive = kind === "error" || kind === "warning";
1891
- return /* @__PURE__ */ jsxs30(
2132
+ return /* @__PURE__ */ jsxs32(
1892
2133
  "div",
1893
2134
  {
1894
2135
  className: cx("pire-msg", className),
@@ -1897,58 +2138,21 @@ function InlineMessage({ kind = "info", title, action, onClose, children, classN
1897
2138
  "aria-live": assertive ? "assertive" : "polite",
1898
2139
  ...rest,
1899
2140
  children: [
1900
- /* @__PURE__ */ jsx37(Icon, { name: KIND_ICON[kind], size: 16, style: { marginTop: 2 } }),
1901
- /* @__PURE__ */ jsxs30("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: "var(--sp-1)" }, children: [
1902
- title ? /* @__PURE__ */ jsx37("span", { className: "pire-msg-title", children: title }) : null,
1903
- children ? /* @__PURE__ */ jsx37("span", { className: "pire-msg-body", children }) : null,
2141
+ /* @__PURE__ */ jsx39(Icon, { name: KIND_ICON[kind], size: 16, style: { marginTop: 2 } }),
2142
+ /* @__PURE__ */ jsxs32("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: "var(--sp-1)" }, children: [
2143
+ title ? /* @__PURE__ */ jsx39("span", { className: "pire-msg-title", children: title }) : null,
2144
+ children ? /* @__PURE__ */ jsx39("span", { className: "pire-msg-body", children }) : null,
1904
2145
  action
1905
2146
  ] }),
1906
- onClose ? /* @__PURE__ */ jsx37(IconButton, { icon: "x", label: msg.inlineMessageDismiss, size: "sm", onPress: onClose }) : null
2147
+ onClose ? /* @__PURE__ */ jsx39(IconButton, { icon: "x", label: msg.inlineMessageDismiss, size: "sm", onPress: onClose }) : null
1907
2148
  ]
1908
2149
  }
1909
2150
  );
1910
2151
  }
1911
2152
 
1912
- // src/components/feedback/ProgressBar.tsx
1913
- import { ProgressBar as AriaProgressBar, Label as Label9 } from "react-aria-components";
1914
- import { Fragment as Fragment2, jsx as jsx38, jsxs as jsxs31 } from "react/jsx-runtime";
1915
- function ProgressBar({
1916
- value = 0,
1917
- minValue = 0,
1918
- maxValue = 100,
1919
- label,
1920
- showValue = true,
1921
- isIndeterminate,
1922
- status = "informative",
1923
- size = "md",
1924
- className,
1925
- style
1926
- }) {
1927
- return /* @__PURE__ */ jsx38(
1928
- AriaProgressBar,
1929
- {
1930
- className: cx("pire-progress", className),
1931
- "data-status": status,
1932
- "data-size": size,
1933
- value,
1934
- minValue,
1935
- maxValue,
1936
- isIndeterminate,
1937
- style,
1938
- children: ({ percentage, valueText }) => /* @__PURE__ */ jsxs31(Fragment2, { children: [
1939
- label || showValue ? /* @__PURE__ */ jsxs31("div", { className: "pire-progress-head", children: [
1940
- label ? /* @__PURE__ */ jsx38(Label9, { children: label }) : /* @__PURE__ */ jsx38("span", {}),
1941
- showValue && !isIndeterminate ? /* @__PURE__ */ jsx38("span", { className: "pire-numeric", children: valueText }) : null
1942
- ] }) : null,
1943
- /* @__PURE__ */ jsx38("div", { className: "pire-progress-track", children: /* @__PURE__ */ jsx38("div", { className: "pire-progress-fill", style: { width: `${isIndeterminate ? 40 : percentage}%` } }) })
1944
- ] })
1945
- }
1946
- );
1947
- }
1948
-
1949
2153
  // src/components/feedback/Toast.tsx
1950
- import * as React11 from "react";
1951
- import { jsx as jsx39, jsxs as jsxs32 } from "react/jsx-runtime";
2154
+ import * as React12 from "react";
2155
+ import { jsx as jsx40, jsxs as jsxs33 } from "react/jsx-runtime";
1952
2156
  var KIND_ICON2 = {
1953
2157
  info: "info",
1954
2158
  success: "check-circle-2",
@@ -1957,7 +2161,7 @@ var KIND_ICON2 = {
1957
2161
  };
1958
2162
  function Toast({ kind = "success", onClose, position = "bottom-center", children, className, ...rest }) {
1959
2163
  const msg = usePireMessages();
1960
- return /* @__PURE__ */ jsxs32(
2164
+ return /* @__PURE__ */ jsxs33(
1961
2165
  "div",
1962
2166
  {
1963
2167
  className: cx("pire-toast", className),
@@ -1966,40 +2170,40 @@ function Toast({ kind = "success", onClose, position = "bottom-center", children
1966
2170
  "aria-live": kind === "error" ? "assertive" : "polite",
1967
2171
  ...rest,
1968
2172
  children: [
1969
- /* @__PURE__ */ jsx39(Icon, { name: KIND_ICON2[kind], size: 16 }),
1970
- /* @__PURE__ */ jsx39("span", { style: { flex: 1 }, children }),
1971
- onClose ? /* @__PURE__ */ jsx39(IconButton, { icon: "x", label: msg.toastDismiss, size: "sm", variant: "inverse", onPress: onClose }) : null
2173
+ /* @__PURE__ */ jsx40(Icon, { name: KIND_ICON2[kind], size: 16 }),
2174
+ /* @__PURE__ */ jsx40("span", { style: { flex: 1 }, children }),
2175
+ onClose ? /* @__PURE__ */ jsx40(IconButton, { icon: "x", label: msg.toastDismiss, size: "sm", variant: "inverse", onPress: onClose }) : null
1972
2176
  ]
1973
2177
  }
1974
2178
  );
1975
2179
  }
1976
- var ToastContext = React11.createContext(null);
2180
+ var ToastContext = React12.createContext(null);
1977
2181
  function ToastProvider({ children, timeout = 6e3 }) {
1978
2182
  const msg = usePireMessages();
1979
- const [toasts, setToasts] = React11.useState([]);
1980
- const close = React11.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
1981
- const add = React11.useCallback((toast) => {
2183
+ const [toasts, setToasts] = React12.useState([]);
2184
+ const close = React12.useCallback((id) => setToasts((t) => t.filter((x) => x.id !== id)), []);
2185
+ const add = React12.useCallback((toast) => {
1982
2186
  const id = Math.random().toString(36).slice(2);
1983
2187
  setToasts((t) => [...t, { ...toast, id }]);
1984
2188
  const ms = toast.timeout ?? timeout;
1985
2189
  if (ms > 0) setTimeout(() => close(id), ms);
1986
2190
  return id;
1987
2191
  }, [close, timeout]);
1988
- const value = React11.useMemo(() => ({ add, close }), [add, close]);
1989
- return /* @__PURE__ */ jsxs32(ToastContext.Provider, { value, children: [
2192
+ const value = React12.useMemo(() => ({ add, close }), [add, close]);
2193
+ return /* @__PURE__ */ jsxs33(ToastContext.Provider, { value, children: [
1990
2194
  children,
1991
- /* @__PURE__ */ jsx39("div", { className: "pire-toast-region", role: "region", "aria-label": msg.toastRegionLabel, children: toasts.map((t) => /* @__PURE__ */ jsx39(Toast, { kind: t.kind, onClose: () => close(t.id), style: { position: "static", transform: "none" }, children: t.message }, t.id)) })
2195
+ /* @__PURE__ */ jsx40("div", { className: "pire-toast-region", role: "region", "aria-label": msg.toastRegionLabel, children: toasts.map((t) => /* @__PURE__ */ jsx40(Toast, { kind: t.kind, onClose: () => close(t.id), style: { position: "static", transform: "none" }, children: t.message }, t.id)) })
1992
2196
  ] });
1993
2197
  }
1994
2198
  function useToast() {
1995
- const ctx = React11.useContext(ToastContext);
2199
+ const ctx = React12.useContext(ToastContext);
1996
2200
  if (!ctx) throw new Error("useToast must be used inside <ToastProvider>");
1997
2201
  return ctx;
1998
2202
  }
1999
2203
 
2000
2204
  // src/components/data/KpiTile.tsx
2001
2205
  import { Button as AriaButton10 } from "react-aria-components";
2002
- import { Fragment as Fragment3, jsx as jsx40, jsxs as jsxs33 } from "react/jsx-runtime";
2206
+ import { Fragment as Fragment3, jsx as jsx41, jsxs as jsxs34 } from "react/jsx-runtime";
2003
2207
  function KpiTile({
2004
2208
  label,
2005
2209
  value,
@@ -2015,50 +2219,50 @@ function KpiTile({
2015
2219
  style
2016
2220
  }) {
2017
2221
  const tone = deltaTone ?? (deltaDirection === "down" ? "negative" : "positive");
2018
- const body = /* @__PURE__ */ jsxs33(Fragment3, { children: [
2019
- /* @__PURE__ */ jsxs33("span", { className: "pire-kpi-label", children: [
2020
- icon ? /* @__PURE__ */ jsx40(Icon, { name: icon, size: 16 }) : null,
2222
+ const body = /* @__PURE__ */ jsxs34(Fragment3, { children: [
2223
+ /* @__PURE__ */ jsxs34("span", { className: "pire-kpi-label", children: [
2224
+ icon ? /* @__PURE__ */ jsx41(Icon, { name: icon, size: 16 }) : null,
2021
2225
  label
2022
2226
  ] }),
2023
- /* @__PURE__ */ jsxs33("span", { className: "pire-kpi-value", children: [
2227
+ /* @__PURE__ */ jsxs34("span", { className: "pire-kpi-value", children: [
2024
2228
  value,
2025
- unit ? /* @__PURE__ */ jsx40("span", { className: "pire-kpi-unit", children: unit }) : null
2229
+ unit ? /* @__PURE__ */ jsx41("span", { className: "pire-kpi-unit", children: unit }) : null
2026
2230
  ] }),
2027
- delta ? /* @__PURE__ */ jsxs33("span", { className: "pire-kpi-delta", "data-tone": tone, children: [
2028
- deltaDirection ? /* @__PURE__ */ jsx40(Icon, { name: deltaDirection === "up" ? "trending-up" : "trending-down", size: 12 }) : null,
2231
+ delta ? /* @__PURE__ */ jsxs34("span", { className: "pire-kpi-delta", "data-tone": tone, children: [
2232
+ deltaDirection ? /* @__PURE__ */ jsx41(Icon, { name: deltaDirection === "up" ? "trending-up" : "trending-down", size: 12 }) : null,
2029
2233
  delta
2030
2234
  ] }) : null,
2031
- footnote ? /* @__PURE__ */ jsx40("span", { className: "pire-kpi-foot", children: footnote }) : null
2235
+ footnote ? /* @__PURE__ */ jsx41("span", { className: "pire-kpi-foot", children: footnote }) : null
2032
2236
  ] });
2033
2237
  const props = { className: cx("pire-kpi", className), "data-status": status, style };
2034
- return onPress ? /* @__PURE__ */ jsx40(AriaButton10, { ...props, "data-pressable": "true", onPress, children: body }) : /* @__PURE__ */ jsx40("div", { ...props, children: body });
2238
+ return onPress ? /* @__PURE__ */ jsx41(AriaButton10, { ...props, "data-pressable": "true", onPress, children: body }) : /* @__PURE__ */ jsx41("div", { ...props, children: body });
2035
2239
  }
2036
2240
 
2037
2241
  // src/components/data/ObjectHeader.tsx
2038
- import { jsx as jsx41, jsxs as jsxs34 } from "react/jsx-runtime";
2242
+ import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
2039
2243
  function ObjectHeader({ title, subtitle, id, breadcrumb, badge, facts, actions, className, ...rest }) {
2040
- return /* @__PURE__ */ jsxs34("header", { className: cx("pire-objheader", className), ...rest, children: [
2244
+ return /* @__PURE__ */ jsxs35("header", { className: cx("pire-objheader", className), ...rest, children: [
2041
2245
  breadcrumb,
2042
- /* @__PURE__ */ jsxs34("div", { className: "pire-objheader-row", children: [
2043
- /* @__PURE__ */ jsxs34("div", { style: { minWidth: 0 }, children: [
2044
- /* @__PURE__ */ jsx41("h1", { className: "pire-objheader-title", children: title }),
2045
- subtitle || id ? /* @__PURE__ */ jsxs34("div", { className: "pire-objheader-sub", children: [
2246
+ /* @__PURE__ */ jsxs35("div", { className: "pire-objheader-row", children: [
2247
+ /* @__PURE__ */ jsxs35("div", { style: { minWidth: 0 }, children: [
2248
+ /* @__PURE__ */ jsx42("h1", { className: "pire-objheader-title", children: title }),
2249
+ subtitle || id ? /* @__PURE__ */ jsxs35("div", { className: "pire-objheader-sub", children: [
2046
2250
  subtitle,
2047
- id ? /* @__PURE__ */ jsx41("span", { className: "pire-objheader-id", children: id }) : null
2251
+ id ? /* @__PURE__ */ jsx42("span", { className: "pire-objheader-id", children: id }) : null
2048
2252
  ] }) : null
2049
2253
  ] }),
2050
2254
  badge,
2051
- actions ? /* @__PURE__ */ jsx41("div", { className: "pire-objheader-actions", children: actions }) : null
2255
+ actions ? /* @__PURE__ */ jsx42("div", { className: "pire-objheader-actions", children: actions }) : null
2052
2256
  ] }),
2053
- facts?.length ? /* @__PURE__ */ jsx41("dl", { className: "pire-facts", style: { margin: 0 }, children: facts.map((fact) => /* @__PURE__ */ jsxs34("div", { children: [
2054
- /* @__PURE__ */ jsx41("dt", { className: "pire-fact-label", children: fact.label }),
2055
- /* @__PURE__ */ jsx41("dd", { className: "pire-fact-value", "data-numeric": fact.numeric ? "true" : void 0, style: { margin: 0 }, children: fact.value })
2257
+ facts?.length ? /* @__PURE__ */ jsx42("dl", { className: "pire-facts", style: { margin: 0 }, children: facts.map((fact) => /* @__PURE__ */ jsxs35("div", { children: [
2258
+ /* @__PURE__ */ jsx42("dt", { className: "pire-fact-label", children: fact.label }),
2259
+ /* @__PURE__ */ jsx42("dd", { className: "pire-fact-value", "data-numeric": fact.numeric ? "true" : void 0, style: { margin: 0 }, children: fact.value })
2056
2260
  ] }, fact.label)) }) : null
2057
2261
  ] });
2058
2262
  }
2059
2263
 
2060
2264
  // src/components/data/FilterBar.tsx
2061
- import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
2265
+ import { jsx as jsx43, jsxs as jsxs36 } from "react/jsx-runtime";
2062
2266
  function FilterBar({
2063
2267
  children,
2064
2268
  activeFilters = [],
@@ -2075,66 +2279,66 @@ function FilterBar({
2075
2279
  const label = useMessage("filterBarLabel", rest["aria-label"]);
2076
2280
  const go = useMessage("filterBarGo", goLabel);
2077
2281
  const clearAll = useMessage("filterBarClearAll", clearAllLabel);
2078
- return /* @__PURE__ */ jsxs35("section", { className: cx("pire-filterbar", className), ...rest, "aria-label": label, children: [
2079
- /* @__PURE__ */ jsxs35("div", { className: "pire-filterbar-controls", children: [
2282
+ return /* @__PURE__ */ jsxs36("section", { className: cx("pire-filterbar", className), ...rest, "aria-label": label, children: [
2283
+ /* @__PURE__ */ jsxs36("div", { className: "pire-filterbar-controls", children: [
2080
2284
  children,
2081
- onGo ? /* @__PURE__ */ jsx42(Button, { variant: "primary", onPress: onGo, children: go }) : null
2285
+ onGo ? /* @__PURE__ */ jsx43(Button, { variant: "primary", onPress: onGo, children: go }) : null
2082
2286
  ] }),
2083
- activeFilters.length || resultLabel || actions ? /* @__PURE__ */ jsxs35("div", { className: "pire-filterbar-foot", children: [
2084
- activeFilters.map((filter) => /* @__PURE__ */ jsx42(Tag, { onRemove: onRemoveFilter ? () => onRemoveFilter(filter.id) : void 0, children: filter.label }, filter.id)),
2085
- activeFilters.length && onClear ? /* @__PURE__ */ jsx42(Button, { variant: "tertiary", size: "sm", onPress: onClear, children: clearAll }) : null,
2086
- resultLabel ? /* @__PURE__ */ jsx42("span", { className: "pire-filterbar-result", "aria-live": "polite", children: resultLabel }) : null,
2087
- actions ? /* @__PURE__ */ jsx42("div", { className: "pire-filterbar-actions", children: actions }) : null
2287
+ activeFilters.length || resultLabel || actions ? /* @__PURE__ */ jsxs36("div", { className: "pire-filterbar-foot", children: [
2288
+ activeFilters.map((filter) => /* @__PURE__ */ jsx43(Tag, { onRemove: onRemoveFilter ? () => onRemoveFilter(filter.id) : void 0, children: filter.label }, filter.id)),
2289
+ activeFilters.length && onClear ? /* @__PURE__ */ jsx43(Button, { variant: "tertiary", size: "sm", onPress: onClear, children: clearAll }) : null,
2290
+ resultLabel ? /* @__PURE__ */ jsx43("span", { className: "pire-filterbar-result", "aria-live": "polite", children: resultLabel }) : null,
2291
+ actions ? /* @__PURE__ */ jsx43("div", { className: "pire-filterbar-actions", children: actions }) : null
2088
2292
  ] }) : null
2089
2293
  ] });
2090
2294
  }
2091
2295
 
2092
2296
  // src/components/data/DescriptionList.tsx
2093
- import { jsx as jsx43, jsxs as jsxs36 } from "react/jsx-runtime";
2297
+ import { jsx as jsx44, jsxs as jsxs37 } from "react/jsx-runtime";
2094
2298
  function DescriptionList({ items, layout = "rows", columns = 3, className, style, ...rest }) {
2095
- return /* @__PURE__ */ jsx43(
2299
+ return /* @__PURE__ */ jsx44(
2096
2300
  "dl",
2097
2301
  {
2098
2302
  className: cx("pire-dl", className),
2099
2303
  "data-layout": layout,
2100
2304
  style: { ...layout === "grid" ? { "--pire-dl-cols": columns } : null, ...style },
2101
2305
  ...rest,
2102
- children: items.map((item, i) => /* @__PURE__ */ jsxs36("div", { className: "pire-dl-row", "data-emphasis": item.emphasis ? "true" : void 0, children: [
2103
- /* @__PURE__ */ jsxs36("dt", { className: "pire-dl-term", children: [
2306
+ children: items.map((item, i) => /* @__PURE__ */ jsxs37("div", { className: "pire-dl-row", "data-emphasis": item.emphasis ? "true" : void 0, children: [
2307
+ /* @__PURE__ */ jsxs37("dt", { className: "pire-dl-term", children: [
2104
2308
  item.label,
2105
2309
  item.hint
2106
2310
  ] }),
2107
- /* @__PURE__ */ jsx43("dd", { className: "pire-dl-value", "data-numeric": item.numeric ? "true" : void 0, children: item.value })
2311
+ /* @__PURE__ */ jsx44("dd", { className: "pire-dl-value", "data-numeric": item.numeric ? "true" : void 0, children: item.value })
2108
2312
  ] }, i))
2109
2313
  }
2110
2314
  );
2111
2315
  }
2112
2316
 
2113
2317
  // src/components/data/Timeline.tsx
2114
- import { jsx as jsx44, jsxs as jsxs37 } from "react/jsx-runtime";
2318
+ import { jsx as jsx45, jsxs as jsxs38 } from "react/jsx-runtime";
2115
2319
  function Timeline({ entries, reverse = false, className, ...rest }) {
2116
2320
  const list = reverse ? [...entries].reverse() : entries;
2117
- return /* @__PURE__ */ jsx44("ol", { className: cx("pire-timeline", className), ...rest, children: list.map((entry, i) => /* @__PURE__ */ jsxs37("li", { className: "pire-timeline-item", children: [
2118
- /* @__PURE__ */ jsx44("span", { className: "pire-timeline-time", children: entry.time }),
2119
- /* @__PURE__ */ jsx44("span", { className: "pire-timeline-text", children: entry.event }),
2120
- entry.actor ? /* @__PURE__ */ jsx44("span", { className: "pire-timeline-actor", children: entry.actor }) : null
2321
+ return /* @__PURE__ */ jsx45("ol", { className: cx("pire-timeline", className), ...rest, children: list.map((entry, i) => /* @__PURE__ */ jsxs38("li", { className: "pire-timeline-item", children: [
2322
+ /* @__PURE__ */ jsx45("span", { className: "pire-timeline-time", children: entry.time }),
2323
+ /* @__PURE__ */ jsx45("span", { className: "pire-timeline-text", children: entry.event }),
2324
+ entry.actor ? /* @__PURE__ */ jsx45("span", { className: "pire-timeline-actor", children: entry.actor }) : null
2121
2325
  ] }, entry.id ?? i)) });
2122
2326
  }
2123
2327
 
2124
2328
  // src/components/data/LinkList.tsx
2125
2329
  import { Button as AriaButton11 } from "react-aria-components";
2126
- import { jsx as jsx45, jsxs as jsxs38 } from "react/jsx-runtime";
2330
+ import { jsx as jsx46, jsxs as jsxs39 } from "react/jsx-runtime";
2127
2331
  function LinkList({ items, onSelect, className, ...rest }) {
2128
- return /* @__PURE__ */ jsx45("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ jsxs38(AriaButton11, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2129
- item.icon ? /* @__PURE__ */ jsx45(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2130
- item.key ? /* @__PURE__ */ jsx45("span", { className: "pire-linklist-key", children: item.key }) : null,
2131
- item.text ? /* @__PURE__ */ jsx45("span", { className: "pire-linklist-text", children: item.text }) : null,
2332
+ return /* @__PURE__ */ jsx46("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ jsxs39(AriaButton11, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2333
+ item.icon ? /* @__PURE__ */ jsx46(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2334
+ item.key ? /* @__PURE__ */ jsx46("span", { className: "pire-linklist-key", children: item.key }) : null,
2335
+ item.text ? /* @__PURE__ */ jsx46("span", { className: "pire-linklist-text", children: item.text }) : null,
2132
2336
  item.trailing
2133
2337
  ] }, item.id)) });
2134
2338
  }
2135
2339
 
2136
2340
  // src/components/layout/PageBand.tsx
2137
- import { jsx as jsx46 } from "react/jsx-runtime";
2341
+ import { jsx as jsx47 } from "react/jsx-runtime";
2138
2342
  function PageBand({
2139
2343
  surface = "card",
2140
2344
  hasBorder = true,
@@ -2142,7 +2346,7 @@ function PageBand({
2142
2346
  className,
2143
2347
  ...rest
2144
2348
  }) {
2145
- return /* @__PURE__ */ jsx46(
2349
+ return /* @__PURE__ */ jsx47(
2146
2350
  "div",
2147
2351
  {
2148
2352
  className: cx("pire-pageband", className),
@@ -2155,56 +2359,56 @@ function PageBand({
2155
2359
  }
2156
2360
 
2157
2361
  // src/components/layout/PageHeader.tsx
2158
- import { jsx as jsx47, jsxs as jsxs39 } from "react/jsx-runtime";
2362
+ import { jsx as jsx48, jsxs as jsxs40 } from "react/jsx-runtime";
2159
2363
  function PageHeader({ title, subtitle, actions, className, ...rest }) {
2160
- return /* @__PURE__ */ jsxs39("header", { className: cx("pire-pageheader", className), ...rest, children: [
2161
- /* @__PURE__ */ jsxs39("div", { style: { minWidth: 0 }, children: [
2162
- /* @__PURE__ */ jsx47("h1", { className: "pire-pageheader-title", children: title }),
2163
- subtitle ? /* @__PURE__ */ jsx47("p", { className: "pire-pageheader-sub", children: subtitle }) : null
2364
+ return /* @__PURE__ */ jsxs40("header", { className: cx("pire-pageheader", className), ...rest, children: [
2365
+ /* @__PURE__ */ jsxs40("div", { style: { minWidth: 0 }, children: [
2366
+ /* @__PURE__ */ jsx48("h1", { className: "pire-pageheader-title", children: title }),
2367
+ subtitle ? /* @__PURE__ */ jsx48("p", { className: "pire-pageheader-sub", children: subtitle }) : null
2164
2368
  ] }),
2165
- actions ? /* @__PURE__ */ jsx47("div", { className: "pire-pageheader-actions", children: actions }) : null
2369
+ actions ? /* @__PURE__ */ jsx48("div", { className: "pire-pageheader-actions", children: actions }) : null
2166
2370
  ] });
2167
2371
  }
2168
2372
 
2169
2373
  // src/components/layout/SectionHeader.tsx
2170
- import { jsx as jsx48, jsxs as jsxs40 } from "react/jsx-runtime";
2374
+ import { jsx as jsx49, jsxs as jsxs41 } from "react/jsx-runtime";
2171
2375
  function SectionHeader({ title, meta, actions, className, ...rest }) {
2172
- return /* @__PURE__ */ jsxs40("div", { className: cx("pire-sectionhead", className), ...rest, children: [
2173
- /* @__PURE__ */ jsx48("span", { className: "pire-eyebrow", children: title }),
2174
- meta ? /* @__PURE__ */ jsx48("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
2175
- actions ? /* @__PURE__ */ jsx48("div", { className: "pire-sectionhead-actions", children: actions }) : null
2376
+ return /* @__PURE__ */ jsxs41("div", { className: cx("pire-sectionhead", className), ...rest, children: [
2377
+ /* @__PURE__ */ jsx49("span", { className: "pire-eyebrow", children: title }),
2378
+ meta ? /* @__PURE__ */ jsx49("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
2379
+ actions ? /* @__PURE__ */ jsx49("div", { className: "pire-sectionhead-actions", children: actions }) : null
2176
2380
  ] });
2177
2381
  }
2178
2382
 
2179
2383
  // src/components/layout/SelectionBar.tsx
2180
- import { jsx as jsx49, jsxs as jsxs41 } from "react/jsx-runtime";
2384
+ import { jsx as jsx50, jsxs as jsxs42 } from "react/jsx-runtime";
2181
2385
  function SelectionBar({ count, noun = "record", children, actions, className, ...rest }) {
2182
2386
  if (!count) return null;
2183
- return /* @__PURE__ */ jsxs41("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
2184
- /* @__PURE__ */ jsxs41("span", { className: "pire-selectionbar-count", children: [
2387
+ return /* @__PURE__ */ jsxs42("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
2388
+ /* @__PURE__ */ jsxs42("span", { className: "pire-selectionbar-count", children: [
2185
2389
  count.toLocaleString(),
2186
2390
  " ",
2187
2391
  noun,
2188
2392
  count === 1 ? "" : "s",
2189
2393
  " selected"
2190
2394
  ] }),
2191
- children ? /* @__PURE__ */ jsx49("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
2192
- actions ? /* @__PURE__ */ jsx49("div", { className: "pire-selectionbar-actions", children: actions }) : null
2395
+ children ? /* @__PURE__ */ jsx50("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
2396
+ actions ? /* @__PURE__ */ jsx50("div", { className: "pire-selectionbar-actions", children: actions }) : null
2193
2397
  ] });
2194
2398
  }
2195
2399
 
2196
2400
  // src/components/layout/FooterBar.tsx
2197
- import { jsx as jsx50, jsxs as jsxs42 } from "react/jsx-runtime";
2401
+ import { jsx as jsx51, jsxs as jsxs43 } from "react/jsx-runtime";
2198
2402
  function FooterBar({ note, actions, children, className, ...rest }) {
2199
- return /* @__PURE__ */ jsxs42("footer", { className: cx("pire-footerbar", className), ...rest, children: [
2200
- note ? /* @__PURE__ */ jsx50("span", { className: "pire-footerbar-note", children: note }) : null,
2403
+ return /* @__PURE__ */ jsxs43("footer", { className: cx("pire-footerbar", className), ...rest, children: [
2404
+ note ? /* @__PURE__ */ jsx51("span", { className: "pire-footerbar-note", children: note }) : null,
2201
2405
  children,
2202
- actions ? /* @__PURE__ */ jsx50("div", { className: "pire-footerbar-actions", children: actions }) : null
2406
+ actions ? /* @__PURE__ */ jsx51("div", { className: "pire-footerbar-actions", children: actions }) : null
2203
2407
  ] });
2204
2408
  }
2205
2409
 
2206
2410
  // src/components/patterns/ConfirmDialog.tsx
2207
- import { Fragment as Fragment4, jsx as jsx51, jsxs as jsxs43 } from "react/jsx-runtime";
2411
+ import { Fragment as Fragment4, jsx as jsx52, jsxs as jsxs44 } from "react/jsx-runtime";
2208
2412
  function ConfirmDialog({
2209
2413
  isOpen,
2210
2414
  title,
@@ -2218,7 +2422,7 @@ function ConfirmDialog({
2218
2422
  onConfirm,
2219
2423
  onCancel
2220
2424
  }) {
2221
- return /* @__PURE__ */ jsxs43(
2425
+ return /* @__PURE__ */ jsxs44(
2222
2426
  Dialog,
2223
2427
  {
2224
2428
  isOpen,
@@ -2228,12 +2432,12 @@ function ConfirmDialog({
2228
2432
  onClose: onCancel,
2229
2433
  isDismissable: !isBusy,
2230
2434
  showClose: false,
2231
- footer: /* @__PURE__ */ jsxs43(Fragment4, { children: [
2232
- /* @__PURE__ */ jsx51(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
2233
- /* @__PURE__ */ jsx51(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
2435
+ footer: /* @__PURE__ */ jsxs44(Fragment4, { children: [
2436
+ /* @__PURE__ */ jsx52(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
2437
+ /* @__PURE__ */ jsx52(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
2234
2438
  ] }),
2235
2439
  children: [
2236
- consequence ? /* @__PURE__ */ jsx51(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
2440
+ consequence ? /* @__PURE__ */ jsx52(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
2237
2441
  children
2238
2442
  ]
2239
2443
  }
@@ -2242,10 +2446,10 @@ function ConfirmDialog({
2242
2446
 
2243
2447
  // src/components/patterns/SidePanel.tsx
2244
2448
  import { ModalOverlay as ModalOverlay2, Modal as Modal2, Dialog as AriaDialog3, Heading as Heading4 } from "react-aria-components";
2245
- import { jsx as jsx52, jsxs as jsxs44 } from "react/jsx-runtime";
2449
+ import { jsx as jsx53, jsxs as jsxs45 } from "react/jsx-runtime";
2246
2450
  function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onClose, className }) {
2247
2451
  const msg = usePireMessages();
2248
- return /* @__PURE__ */ jsx52(
2452
+ return /* @__PURE__ */ jsx53(
2249
2453
  ModalOverlay2,
2250
2454
  {
2251
2455
  className: "pire-sidepanel-overlay",
@@ -2254,34 +2458,138 @@ function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onC
2254
2458
  onOpenChange: (o) => {
2255
2459
  if (!o) onClose?.();
2256
2460
  },
2257
- children: /* @__PURE__ */ jsx52(Modal2, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ jsxs44(AriaDialog3, { className: "pire-dialog", style: { height: "100%" }, children: [
2258
- /* @__PURE__ */ jsxs44("header", { className: "pire-dialog-head", children: [
2259
- /* @__PURE__ */ jsxs44("div", { style: { flex: 1, minWidth: 0 }, children: [
2260
- /* @__PURE__ */ jsx52(Heading4, { slot: "title", className: "pire-dialog-title", children: title }),
2261
- subtitle ? /* @__PURE__ */ jsx52("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
2461
+ children: /* @__PURE__ */ jsx53(Modal2, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ jsxs45(AriaDialog3, { className: "pire-dialog", style: { height: "100%" }, children: [
2462
+ /* @__PURE__ */ jsxs45("header", { className: "pire-dialog-head", children: [
2463
+ /* @__PURE__ */ jsxs45("div", { style: { flex: 1, minWidth: 0 }, children: [
2464
+ /* @__PURE__ */ jsx53(Heading4, { slot: "title", className: "pire-dialog-title", children: title }),
2465
+ subtitle ? /* @__PURE__ */ jsx53("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
2262
2466
  ] }),
2263
- /* @__PURE__ */ jsx52(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
2467
+ /* @__PURE__ */ jsx53(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
2264
2468
  ] }),
2265
- /* @__PURE__ */ jsx52("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
2266
- footer ? /* @__PURE__ */ jsx52("footer", { className: "pire-dialog-foot", children: footer }) : null
2469
+ /* @__PURE__ */ jsx53("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
2470
+ footer ? /* @__PURE__ */ jsx53("footer", { className: "pire-dialog-foot", children: footer }) : null
2267
2471
  ] }) })
2268
2472
  }
2269
2473
  );
2270
2474
  }
2271
2475
 
2272
2476
  // src/components/patterns/EmptyState.tsx
2273
- import { jsx as jsx53, jsxs as jsxs45 } from "react/jsx-runtime";
2477
+ import { jsx as jsx54, jsxs as jsxs46 } from "react/jsx-runtime";
2274
2478
  function EmptyState({ icon = "file-text", title, action, compact, children, className, ...rest }) {
2275
- return /* @__PURE__ */ jsxs45("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
2276
- /* @__PURE__ */ jsx53(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
2277
- title ? /* @__PURE__ */ jsx53("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
2278
- children ? /* @__PURE__ */ jsx53("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
2479
+ return /* @__PURE__ */ jsxs46("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
2480
+ /* @__PURE__ */ jsx54(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
2481
+ title ? /* @__PURE__ */ jsx54("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
2482
+ children ? /* @__PURE__ */ jsx54("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
2279
2483
  action
2280
2484
  ] });
2281
2485
  }
2282
2486
 
2487
+ // src/components/patterns/FileDropZone.tsx
2488
+ import * as React13 from "react";
2489
+ import { DropZone, FileTrigger as FileTrigger2, isFileDropItem } from "react-aria-components";
2490
+ import { jsx as jsx55, jsxs as jsxs47 } from "react/jsx-runtime";
2491
+ var isImage2 = (file) => file.type.startsWith("image/");
2492
+ function FileDropZone({
2493
+ label,
2494
+ value,
2495
+ defaultValue,
2496
+ onChange,
2497
+ acceptedFileTypes,
2498
+ allowsMultiple,
2499
+ maxSize,
2500
+ onError,
2501
+ showPreview = true,
2502
+ uploadProgress,
2503
+ promptLabel,
2504
+ height = "regular",
2505
+ description,
2506
+ errorMessage,
2507
+ isInvalid,
2508
+ isDisabled,
2509
+ isReadOnly,
2510
+ isRequired,
2511
+ fullWidth = true,
2512
+ className,
2513
+ style
2514
+ }) {
2515
+ const msg = usePireMessages();
2516
+ const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
2517
+ const files = value ?? uncontrolled;
2518
+ const created = React13.useRef([]);
2519
+ React13.useEffect(() => () => {
2520
+ for (const url of created.current) URL.revokeObjectURL(url);
2521
+ }, []);
2522
+ const commit = (next) => {
2523
+ if (value === void 0) setUncontrolled(next);
2524
+ onChange?.(next);
2525
+ };
2526
+ const accept = (picked) => {
2527
+ if (isDisabled || isReadOnly || !picked.length) return;
2528
+ const { accepted, rejected } = screenFiles(picked, { maxSize, acceptedFileTypes });
2529
+ if (rejected.length) onError?.(rejected);
2530
+ if (!accepted.length) return;
2531
+ const wrapped = accepted.map((file) => {
2532
+ const previewUrl = showPreview && isImage2(file) ? URL.createObjectURL(file) : void 0;
2533
+ if (previewUrl) created.current.push(previewUrl);
2534
+ return { file, previewUrl };
2535
+ });
2536
+ commit(allowsMultiple ? [...files, ...wrapped] : wrapped.slice(0, 1));
2537
+ };
2538
+ const remove = (target) => commit(files.filter((f) => f.file !== target));
2539
+ return /* @__PURE__ */ jsxs47("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
2540
+ label ? /* @__PURE__ */ jsxs47("span", { className: "pire-field-label", children: [
2541
+ label,
2542
+ isRequired ? /* @__PURE__ */ jsx55("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
2543
+ ] }) : null,
2544
+ /* @__PURE__ */ jsxs47(
2545
+ DropZone,
2546
+ {
2547
+ className: "pire-dropzone",
2548
+ "data-height": height,
2549
+ isDisabled: isDisabled || isReadOnly,
2550
+ onDrop: async (e) => {
2551
+ const dropped = await Promise.all(
2552
+ e.items.filter(isFileDropItem).map((item) => item.getFile())
2553
+ );
2554
+ accept(dropped);
2555
+ },
2556
+ children: [
2557
+ /* @__PURE__ */ jsx55(Icon, { name: "download", size: 24, className: "pire-dropzone-icon" }),
2558
+ /* @__PURE__ */ jsx55("span", { className: "pire-dropzone-prompt", children: promptLabel ?? msg.fileDropZonePrompt }),
2559
+ /* @__PURE__ */ jsx55(
2560
+ FileTrigger2,
2561
+ {
2562
+ acceptedFileTypes,
2563
+ allowsMultiple,
2564
+ onSelect: (list) => accept(list ? [...list] : []),
2565
+ children: /* @__PURE__ */ jsx55(Button, { variant: "secondary", isDisabled: isDisabled || isReadOnly, children: msg.fileUploadChoose })
2566
+ }
2567
+ )
2568
+ ]
2569
+ }
2570
+ ),
2571
+ files.length ? /* @__PURE__ */ jsx55("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ jsxs47("li", { className: "pire-fileupload-item", children: [
2572
+ previewUrl ? /* @__PURE__ */ jsx55("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ jsx55(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
2573
+ /* @__PURE__ */ jsx55("span", { className: "pire-fileupload-name", children: file.name }),
2574
+ /* @__PURE__ */ jsx55("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
2575
+ isDisabled || isReadOnly ? null : /* @__PURE__ */ jsx55(
2576
+ IconButton,
2577
+ {
2578
+ icon: "x",
2579
+ size: "sm",
2580
+ label: msg.fileUploadRemoveNamed.replace("{name}", file.name),
2581
+ onPress: () => remove(file)
2582
+ }
2583
+ )
2584
+ ] }, `${file.name}-${file.size}-${file.lastModified}`)) }) : null,
2585
+ uploadProgress != null ? /* @__PURE__ */ jsx55(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
2586
+ description ? /* @__PURE__ */ jsx55("span", { className: "pire-field-hint", children: description }) : null,
2587
+ isInvalid && errorMessage ? /* @__PURE__ */ jsx55("span", { className: "pire-field-error", children: errorMessage }) : null
2588
+ ] });
2589
+ }
2590
+
2283
2591
  // src/index.ts
2284
- import { DialogTrigger, MenuTrigger, SubmenuTrigger, Popover as Popover5, RouterProvider, I18nProvider } from "react-aria-components";
2592
+ import { DialogTrigger, MenuTrigger as MenuTrigger2, SubmenuTrigger, Popover as Popover6, RouterProvider, I18nProvider } from "react-aria-components";
2285
2593
  export {
2286
2594
  Avatar,
2287
2595
  Badge,
@@ -2297,6 +2605,8 @@ export {
2297
2605
  Dialog,
2298
2606
  DialogTrigger,
2299
2607
  EmptyState,
2608
+ FileDropZone,
2609
+ FileUpload,
2300
2610
  FilterBar,
2301
2611
  FooterBar,
2302
2612
  FormField,
@@ -2313,7 +2623,7 @@ export {
2313
2623
  MenuItem,
2314
2624
  MenuSection,
2315
2625
  MenuSeparator,
2316
- MenuTrigger,
2626
+ MenuTrigger2 as MenuTrigger,
2317
2627
  MultiComboBox,
2318
2628
  NumberField,
2319
2629
  ObjectHeader,
@@ -2321,7 +2631,7 @@ export {
2321
2631
  PageHeader,
2322
2632
  Pagination,
2323
2633
  PireIntlProvider,
2324
- Popover5 as Popover,
2634
+ Popover6 as Popover,
2325
2635
  ProgressBar,
2326
2636
  Radio,
2327
2637
  RadioGroup,
@@ -2352,6 +2662,7 @@ export {
2352
2662
  configureIcons,
2353
2663
  enMessages,
2354
2664
  esMessages,
2665
+ formatFileSize,
2355
2666
  usePireMessages,
2356
2667
  useToast
2357
2668
  };