@orianatech/pire 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1515,6 +1515,15 @@ function typeIntoInput(el, text) {
1515
1515
  const caret = start + text.length;
1516
1516
  el.setSelectionRange(caret, caret);
1517
1517
  }
1518
+ function toAriaNumber(value) {
1519
+ if (value === void 0) {
1520
+ return void 0;
1521
+ }
1522
+ if (value === null || value === "") {
1523
+ return NaN;
1524
+ }
1525
+ return typeof value === "number" ? value : Number(value);
1526
+ }
1518
1527
  function NumberField({
1519
1528
  label,
1520
1529
  suffix,
@@ -1525,10 +1534,16 @@ function NumberField({
1525
1534
  fullWidth = true,
1526
1535
  className,
1527
1536
  style,
1537
+ value,
1538
+ defaultValue,
1539
+ onChange,
1540
+ emptyValue,
1528
1541
  ...rest
1529
1542
  }) {
1530
1543
  const msg = usePireMessages();
1531
1544
  const { locale } = (0, import_react_aria_components17.useLocale)();
1545
+ const empty = emptyValue === void 0 ? NaN : emptyValue;
1546
+ const handleChange = onChange && ((next) => onChange(Number.isNaN(next) ? empty : next));
1532
1547
  const handleDecimalKey = (event) => {
1533
1548
  if (event.key !== "." || event.ctrlKey || event.metaKey || event.altKey) {
1534
1549
  return;
@@ -1547,36 +1562,77 @@ function NumberField({
1547
1562
  event.preventDefault();
1548
1563
  typeIntoInput(event.currentTarget, separator);
1549
1564
  };
1550
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_aria_components17.NumberField, { className: cx("pire-field", className), style, validationBehavior: "aria", ...rest, children: [
1551
- label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_aria_components17.Label, { className: "pire-field-label", children: [
1552
- label,
1553
- rest.isRequired ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1554
- ] }) : null,
1555
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1556
- import_react_aria_components17.Group,
1557
- {
1558
- className: "pire-control",
1559
- "data-size": size,
1560
- "data-full-width": String(fullWidth),
1561
- "data-invalid": rest.isInvalid ? "true" : void 0,
1562
- "data-readonly": rest.isReadOnly ? "true" : void 0,
1563
- children: [
1564
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Input, { className: "pire-input", "data-numeric": "true", onKeyDown: handleDecimalKey }),
1565
- suffix ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "pire-affix", children: suffix }) : null,
1566
- hideStepper ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "pire-stepper", children: [
1567
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Button, { slot: "increment", className: "pire-stepper-btn", "aria-label": msg.numberFieldIncrease, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { name: "plus", size: 10 }) }),
1568
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Button, { slot: "decrement", className: "pire-stepper-btn", "aria-label": msg.numberFieldDecrease, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { name: "minus", size: 10 }) })
1569
- ] })
1570
- ]
1571
- }
1572
- ),
1573
- description ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Text, { slot: "description", className: "pire-field-hint", children: description }) : null,
1574
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.FieldError, { className: "pire-field-error", children: errorMessage })
1575
- ] });
1565
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1566
+ import_react_aria_components17.NumberField,
1567
+ {
1568
+ className: cx("pire-field", className),
1569
+ style,
1570
+ validationBehavior: "aria",
1571
+ value: toAriaNumber(value),
1572
+ defaultValue: toAriaNumber(defaultValue),
1573
+ onChange: handleChange,
1574
+ ...rest,
1575
+ children: [
1576
+ label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_aria_components17.Label, { className: "pire-field-label", children: [
1577
+ label,
1578
+ rest.isRequired ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1579
+ ] }) : null,
1580
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1581
+ import_react_aria_components17.Group,
1582
+ {
1583
+ className: "pire-control",
1584
+ "data-size": size,
1585
+ "data-full-width": String(fullWidth),
1586
+ "data-invalid": rest.isInvalid ? "true" : void 0,
1587
+ "data-readonly": rest.isReadOnly ? "true" : void 0,
1588
+ children: [
1589
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Input, { className: "pire-input", "data-numeric": "true", onKeyDown: handleDecimalKey }),
1590
+ suffix ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "pire-affix", children: suffix }) : null,
1591
+ hideStepper ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "pire-stepper", children: [
1592
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Button, { slot: "increment", className: "pire-stepper-btn", "aria-label": msg.numberFieldIncrease, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { name: "plus", size: 10 }) }),
1593
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Button, { slot: "decrement", className: "pire-stepper-btn", "aria-label": msg.numberFieldDecrease, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { name: "minus", size: 10 }) })
1594
+ ] })
1595
+ ]
1596
+ }
1597
+ ),
1598
+ description ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.Text, { slot: "description", className: "pire-field-hint", children: description }) : null,
1599
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_aria_components17.FieldError, { className: "pire-field-error", children: errorMessage })
1600
+ ]
1601
+ }
1602
+ );
1576
1603
  }
1577
1604
 
1578
1605
  // src/components/forms/DatePicker.tsx
1579
1606
  var import_react_aria_components18 = require("react-aria-components");
1607
+
1608
+ // src/components/forms/dateValues.ts
1609
+ var import_date = require("@internationalized/date");
1610
+ var ISO_DATE = /^(\d{4}-\d{2}-\d{2})(?:[T ].*)?$/;
1611
+ function coerceDateValue(value) {
1612
+ if (value === void 0) {
1613
+ return void 0;
1614
+ }
1615
+ if (value === null || value === "") {
1616
+ return null;
1617
+ }
1618
+ if (typeof value !== "string") {
1619
+ return value;
1620
+ }
1621
+ const match = ISO_DATE.exec(value);
1622
+ if (!match) {
1623
+ return null;
1624
+ }
1625
+ try {
1626
+ return (0, import_date.parseDate)(match[1]);
1627
+ } catch {
1628
+ return null;
1629
+ }
1630
+ }
1631
+ function coerceBound(value) {
1632
+ return coerceDateValue(value) ?? void 0;
1633
+ }
1634
+
1635
+ // src/components/forms/DatePicker.tsx
1580
1636
  var import_jsx_runtime26 = require("react/jsx-runtime");
1581
1637
  function DatePicker({
1582
1638
  label,
@@ -1586,49 +1642,88 @@ function DatePicker({
1586
1642
  fullWidth = true,
1587
1643
  className,
1588
1644
  style,
1645
+ value,
1646
+ defaultValue,
1647
+ onChange,
1648
+ valueFormat,
1649
+ minValue,
1650
+ maxValue,
1589
1651
  ...rest
1590
1652
  }) {
1591
1653
  const msg = usePireMessages();
1592
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.DatePicker, { className: cx("pire-field", className), style, validationBehavior: "aria", ...rest, children: [
1593
- label ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.Label, { className: "pire-field-label", children: [
1594
- label,
1595
- rest.isRequired ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1596
- ] }) : null,
1597
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1598
- import_react_aria_components18.Group,
1599
- {
1600
- className: "pire-control",
1601
- "data-size": size,
1602
- "data-full-width": String(fullWidth),
1603
- "data-invalid": rest.isInvalid ? "true" : void 0,
1604
- "data-readonly": rest.isReadOnly ? "true" : void 0,
1605
- children: [
1606
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.DateInput, { className: "pire-datefield", children: (segment) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.DateSegment, { segment, className: "pire-datesegment" }) }),
1607
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerOpenCalendar, style: { width: 24, height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "calendar", size: 16 }) })
1608
- ]
1609
- }
1610
- ),
1611
- description ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Text, { slot: "description", className: "pire-field-hint", children: description }) : null,
1612
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.FieldError, { className: "pire-field-error", children: errorMessage }),
1613
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Popover, { className: "pire-popover", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Dialog, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.Calendar, { className: "pire-calendar", children: [
1614
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("header", { className: "pire-calendar-head", children: [
1615
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { slot: "previous", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerPreviousMonth, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "chevron-left", size: 16 }) }),
1616
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Heading, { className: "pire-calendar-title" }),
1617
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { slot: "next", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerNextMonth, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "chevron-right", size: 16 }) })
1618
- ] }),
1619
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.CalendarGrid, { className: "pire-calendar-grid", children: [
1620
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarGridHeader, { children: (day) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarHeaderCell, { children: day }) }),
1621
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarGridBody, { children: (date) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarCell, { date, className: "pire-calendar-cell" }) })
1622
- ] })
1623
- ] }) }) })
1624
- ] });
1654
+ const handleChange = onChange && ((next) => onChange(
1655
+ valueFormat === "iso" && next ? next.toString() : next
1656
+ ));
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1658
+ import_react_aria_components18.DatePicker,
1659
+ {
1660
+ className: cx("pire-field", className),
1661
+ style,
1662
+ validationBehavior: "aria",
1663
+ value: coerceDateValue(value),
1664
+ defaultValue: coerceDateValue(defaultValue),
1665
+ minValue: coerceBound(minValue),
1666
+ maxValue: coerceBound(maxValue),
1667
+ onChange: handleChange,
1668
+ ...rest,
1669
+ children: [
1670
+ label ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.Label, { className: "pire-field-label", children: [
1671
+ label,
1672
+ rest.isRequired ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
1673
+ ] }) : null,
1674
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1675
+ import_react_aria_components18.Group,
1676
+ {
1677
+ className: "pire-control",
1678
+ "data-size": size,
1679
+ "data-full-width": String(fullWidth),
1680
+ "data-invalid": rest.isInvalid ? "true" : void 0,
1681
+ "data-readonly": rest.isReadOnly ? "true" : void 0,
1682
+ children: [
1683
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.DateInput, { className: "pire-datefield", children: (segment) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.DateSegment, { segment, className: "pire-datesegment" }) }),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerOpenCalendar, style: { width: 24, height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "calendar", size: 16 }) })
1685
+ ]
1686
+ }
1687
+ ),
1688
+ description ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Text, { slot: "description", className: "pire-field-hint", children: description }) : null,
1689
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.FieldError, { className: "pire-field-error", children: errorMessage }),
1690
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Popover, { className: "pire-popover", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Dialog, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.Calendar, { className: "pire-calendar", children: [
1691
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("header", { className: "pire-calendar-head", children: [
1692
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { slot: "previous", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerPreviousMonth, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "chevron-left", size: 16 }) }),
1693
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Heading, { className: "pire-calendar-title" }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.Button, { slot: "next", className: "pire-iconbtn", "data-size": "sm", "aria-label": msg.datePickerNextMonth, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "chevron-right", size: 16 }) })
1695
+ ] }),
1696
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_aria_components18.CalendarGrid, { className: "pire-calendar-grid", children: [
1697
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarGridHeader, { children: (day) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarHeaderCell, { children: day }) }),
1698
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarGridBody, { children: (date) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_aria_components18.CalendarCell, { date, className: "pire-calendar-cell" }) })
1699
+ ] })
1700
+ ] }) }) })
1701
+ ]
1702
+ }
1703
+ );
1625
1704
  }
1626
1705
 
1627
1706
  // src/components/forms/DateRangePicker.tsx
1628
1707
  var import_react_aria_components19 = require("react-aria-components");
1629
1708
  var import_jsx_runtime27 = require("react/jsx-runtime");
1709
+ function coerceRange(range) {
1710
+ if (range === void 0) {
1711
+ return void 0;
1712
+ }
1713
+ if (range === null) {
1714
+ return null;
1715
+ }
1716
+ const start = coerceDateValue(range.start) ?? null;
1717
+ const end = coerceDateValue(range.end) ?? null;
1718
+ return start === null && end === null ? null : { start, end };
1719
+ }
1630
1720
  function rangeLengthInDays(range) {
1631
- return range.end.toDate("UTC").getTime() / 864e5 - range.start.toDate("UTC").getTime() / 864e5 + 1;
1721
+ const start = coerceDateValue(range?.start) ?? null;
1722
+ const end = coerceDateValue(range?.end) ?? null;
1723
+ if (start === null || end === null) {
1724
+ return null;
1725
+ }
1726
+ return end.toDate("UTC").getTime() / 864e5 - start.toDate("UTC").getTime() / 864e5 + 1;
1632
1727
  }
1633
1728
  function DateRangePicker({
1634
1729
  label,
@@ -1642,11 +1737,28 @@ function DateRangePicker({
1642
1737
  endName,
1643
1738
  className,
1644
1739
  style,
1740
+ value,
1741
+ defaultValue,
1742
+ onChange,
1743
+ valueFormat,
1744
+ minValue,
1745
+ maxValue,
1645
1746
  ...rest
1646
1747
  }) {
1647
1748
  const msg = usePireMessages();
1648
- const current = rest.value ?? rest.defaultValue ?? null;
1649
- const tooLong = maxRangeDays != null && current != null && rangeLengthInDays(current) > maxRangeDays;
1749
+ const current = coerceRange(value) ?? coerceRange(defaultValue) ?? null;
1750
+ const span = current === null ? null : rangeLengthInDays(current);
1751
+ const tooLong = maxRangeDays != null && span != null && span > maxRangeDays;
1752
+ const emit = (next) => {
1753
+ if (!onChange) {
1754
+ return;
1755
+ }
1756
+ if (!next?.start || !next.end) {
1757
+ onChange(null);
1758
+ return;
1759
+ }
1760
+ onChange(valueFormat === "iso" ? { start: next.start.toString(), end: next.end.toString() } : { start: next.start, end: next.end });
1761
+ };
1650
1762
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1651
1763
  import_react_aria_components19.DateRangePicker,
1652
1764
  {
@@ -1655,8 +1767,13 @@ function DateRangePicker({
1655
1767
  startName,
1656
1768
  endName,
1657
1769
  validationBehavior: "aria",
1770
+ value: coerceRange(value),
1771
+ defaultValue: coerceRange(defaultValue),
1772
+ minValue: coerceBound(minValue),
1773
+ maxValue: coerceBound(maxValue),
1774
+ onChange: onChange && emit,
1658
1775
  ...rest,
1659
- isInvalid: rest.isInvalid || tooLong,
1776
+ isInvalid: rest.isInvalid || tooLong || void 0,
1660
1777
  children: [
1661
1778
  label ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react_aria_components19.Label, { className: "pire-field-label", children: [
1662
1779
  label,
@@ -1697,7 +1814,7 @@ function DateRangePicker({
1697
1814
  import_react_aria_components19.Button,
1698
1815
  {
1699
1816
  className: "pire-daterange-preset",
1700
- onPress: () => rest.onChange?.(preset.range()),
1817
+ onPress: () => emit(coerceRange(preset.range()) ?? null),
1701
1818
  children: preset.label
1702
1819
  },
1703
1820
  preset.id