@auronui/vue 1.0.9 → 1.0.11

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.
@@ -1454,6 +1454,7 @@ function useFormInject() {
1454
1454
  //#endregion
1455
1455
  //#region src/components/form/validation.ts
1456
1456
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1457
+ var URL_REGEX = /^(https?:\/\/)?([\w-]+\.)+[\w-]+(\/[\w\-./?%&=]*)?$/i;
1457
1458
  function isEmpty(value) {
1458
1459
  if (value === void 0 || value === null || value === "" || value === false) return true;
1459
1460
  if (Array.isArray(value) && value.length === 0) return true;
@@ -1483,20 +1484,35 @@ function resolvePatternRule(rule) {
1483
1484
  };
1484
1485
  return rule;
1485
1486
  }
1486
- async function runValidation(value, rules, validate) {
1487
+ function resolveStringRule(rule) {
1488
+ if (typeof rule === "string") return {
1489
+ value: rule,
1490
+ message: void 0
1491
+ };
1492
+ return rule;
1493
+ }
1494
+ async function runValidation(value, rules, validate, context) {
1487
1495
  if (!rules && !validate) return void 0;
1488
1496
  if (rules?.required !== void 0) {
1489
1497
  const { enabled, message } = resolveSimpleRule(rules.required);
1490
1498
  if (enabled && isEmpty(value)) return message ?? "This field is required";
1491
1499
  }
1492
1500
  if (isEmpty(value)) {
1493
- if (validate) return await validate(value);
1501
+ if (validate) return await validate(value, context);
1494
1502
  return;
1495
1503
  }
1496
1504
  if (rules?.email !== void 0) {
1497
1505
  const { enabled, message } = resolveSimpleRule(rules.email);
1498
1506
  if (enabled && !EMAIL_REGEX.test(String(value))) return message ?? "Enter a valid email address";
1499
1507
  }
1508
+ if (rules?.url !== void 0) {
1509
+ const { enabled, message } = resolveSimpleRule(rules.url);
1510
+ if (enabled && !URL_REGEX.test(String(value))) return message ?? "Enter a valid URL";
1511
+ }
1512
+ if (rules?.integer !== void 0) {
1513
+ const { enabled, message } = resolveSimpleRule(rules.integer);
1514
+ if (enabled && !Number.isInteger(Number(value))) return message ?? "Must be a whole number";
1515
+ }
1500
1516
  if (rules?.pattern !== void 0) {
1501
1517
  const { value: regex, message } = resolvePatternRule(rules.pattern);
1502
1518
  if (!regex.test(String(value))) return message ?? "Invalid format";
@@ -1517,7 +1533,11 @@ async function runValidation(value, rules, validate) {
1517
1533
  const { value: maxVal, message } = resolveNumericRule(rules.max);
1518
1534
  if (Number(value) > maxVal) return message ?? `Must be at most ${maxVal}`;
1519
1535
  }
1520
- if (validate) return await validate(value);
1536
+ if (rules?.matches !== void 0) {
1537
+ const { value: fieldName, message } = resolveStringRule(rules.matches);
1538
+ if (value !== context?.values[fieldName]) return message ?? `Must match ${fieldName}`;
1539
+ }
1540
+ if (validate) return await validate(value, context);
1521
1541
  }
1522
1542
  //#endregion
1523
1543
  //#region src/components/form/Form.vue
@@ -1531,31 +1551,75 @@ var Form_default = /* @__PURE__ */ (0, vue.defineComponent)({
1531
1551
  },
1532
1552
  class: { default: void 0 }
1533
1553
  },
1534
- emits: ["submit", "invalid"],
1535
- setup(__props, { emit: __emit }) {
1554
+ emits: [
1555
+ "submit",
1556
+ "invalid",
1557
+ "reset"
1558
+ ],
1559
+ setup(__props, { expose: __expose, emit: __emit }) {
1536
1560
  const props = __props;
1537
1561
  const emit = __emit;
1538
1562
  const errors = (0, vue.ref)({});
1539
1563
  const isSubmitting = (0, vue.ref)(false);
1564
+ const isSubmitted = (0, vue.ref)(false);
1565
+ const submitCount = (0, vue.ref)(0);
1540
1566
  const fields = /* @__PURE__ */ new Map();
1567
+ const fieldCount = (0, vue.ref)(0);
1541
1568
  function registerField(reg) {
1542
1569
  fields.set(reg.name, reg);
1570
+ fieldCount.value++;
1543
1571
  }
1544
1572
  function unregisterField(name) {
1545
1573
  fields.delete(name);
1574
+ fieldCount.value--;
1546
1575
  const next = { ...errors.value };
1547
1576
  delete next[name];
1548
1577
  errors.value = next;
1549
1578
  }
1579
+ const isValid = (0, vue.computed)(() => {
1580
+ fieldCount.value;
1581
+ return Object.keys(errors.value).length === 0;
1582
+ });
1583
+ const isDirty = (0, vue.computed)(() => {
1584
+ fieldCount.value;
1585
+ for (const field of fields.values()) if (field.dirty.value) return true;
1586
+ return false;
1587
+ });
1588
+ const isTouched = (0, vue.computed)(() => {
1589
+ fieldCount.value;
1590
+ for (const field of fields.values()) if (field.touched.value) return true;
1591
+ return false;
1592
+ });
1593
+ function getAllValues() {
1594
+ const values = {};
1595
+ for (const [name, field] of fields.entries()) values[name] = field.getValue();
1596
+ return values;
1597
+ }
1550
1598
  async function triggerFieldValidation(name) {
1551
1599
  const field = fields.get(name);
1552
1600
  if (!field) return;
1553
- const error = await runValidation(field.getValue(), field.rules, field.validate);
1601
+ const error = await runValidation(field.getValue(), field.rules, field.validate, { values: getAllValues() });
1554
1602
  const next = { ...errors.value };
1555
1603
  if (error) next[name] = error;
1556
1604
  else delete next[name];
1557
1605
  errors.value = next;
1558
1606
  }
1607
+ async function trigger(name) {
1608
+ if (name) {
1609
+ await triggerFieldValidation(name);
1610
+ return !errors.value[name];
1611
+ }
1612
+ const results = await Promise.all([...fields.entries()].map(async ([fieldName, field]) => {
1613
+ return {
1614
+ name: fieldName,
1615
+ error: await runValidation(field.getValue(), field.rules, field.validate, { values: getAllValues() })
1616
+ };
1617
+ }));
1618
+ const next = {};
1619
+ for (const { name: fieldName, error } of results) if (error) next[fieldName] = error;
1620
+ errors.value = next;
1621
+ return Object.keys(next).length === 0;
1622
+ }
1559
1623
  function setErrors(newErrors) {
1560
1624
  errors.value = {
1561
1625
  ...errors.value,
@@ -1563,12 +1627,43 @@ var Form_default = /* @__PURE__ */ (0, vue.defineComponent)({
1563
1627
  };
1564
1628
  isSubmitting.value = false;
1565
1629
  }
1630
+ function setError(name, message) {
1631
+ errors.value = {
1632
+ ...errors.value,
1633
+ [name]: message
1634
+ };
1635
+ }
1636
+ function clearErrors(name) {
1637
+ if (name) {
1638
+ const next = { ...errors.value };
1639
+ delete next[name];
1640
+ errors.value = next;
1641
+ } else errors.value = {};
1642
+ }
1643
+ function getValues() {
1644
+ return getAllValues();
1645
+ }
1646
+ function setValue(name, value) {
1647
+ const field = fields.get(name);
1648
+ if (field) field.setValue(value);
1649
+ }
1650
+ function reset() {
1651
+ for (const field of fields.values()) field.reset();
1652
+ errors.value = {};
1653
+ isSubmitting.value = false;
1654
+ isSubmitted.value = false;
1655
+ submitCount.value = 0;
1656
+ emit("reset");
1657
+ }
1566
1658
  async function handleSubmit() {
1567
1659
  isSubmitting.value = true;
1660
+ submitCount.value++;
1661
+ const values = getAllValues();
1662
+ const context = { values };
1568
1663
  const results = await Promise.all([...fields.entries()].map(async ([name, field]) => {
1569
1664
  return {
1570
1665
  name,
1571
- error: await runValidation(field.getValue(), field.rules, field.validate)
1666
+ error: await runValidation(field.getValue(), field.rules, field.validate, context)
1572
1667
  };
1573
1668
  }));
1574
1669
  const nextErrors = {};
@@ -1576,12 +1671,13 @@ var Form_default = /* @__PURE__ */ (0, vue.defineComponent)({
1576
1671
  if (Object.keys(nextErrors).length > 0) {
1577
1672
  errors.value = nextErrors;
1578
1673
  isSubmitting.value = false;
1674
+ isSubmitted.value = true;
1579
1675
  emit("invalid", nextErrors);
1580
1676
  return;
1581
1677
  }
1582
1678
  errors.value = {};
1583
- const values = {};
1584
- for (const [name, field] of fields.entries()) values[name] = field.getValue();
1679
+ isSubmitted.value = true;
1680
+ isSubmitting.value = false;
1585
1681
  emit("submit", {
1586
1682
  values,
1587
1683
  setErrors
@@ -1590,12 +1686,39 @@ var Form_default = /* @__PURE__ */ (0, vue.defineComponent)({
1590
1686
  (0, vue.provide)(formContextKey, {
1591
1687
  errors,
1592
1688
  isSubmitting,
1689
+ isSubmitted,
1690
+ submitCount,
1593
1691
  isDisabled: (0, vue.computed)(() => props.isDisabled),
1692
+ isValid,
1693
+ isDirty,
1694
+ isTouched,
1594
1695
  validationMode: (0, vue.computed)(() => props.validationMode),
1595
1696
  registerField,
1596
1697
  unregisterField,
1597
1698
  triggerFieldValidation,
1598
- setErrors
1699
+ setErrors,
1700
+ setError,
1701
+ clearErrors,
1702
+ getValues,
1703
+ setValue,
1704
+ trigger,
1705
+ reset
1706
+ });
1707
+ __expose({
1708
+ errors,
1709
+ isSubmitting,
1710
+ isSubmitted,
1711
+ submitCount,
1712
+ isValid,
1713
+ isDirty,
1714
+ isTouched,
1715
+ getValues,
1716
+ setValue,
1717
+ setErrors,
1718
+ setError,
1719
+ clearErrors,
1720
+ trigger,
1721
+ reset
1599
1722
  });
1600
1723
  return (_ctx, _cache) => {
1601
1724
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("form", {
@@ -1604,8 +1727,20 @@ var Form_default = /* @__PURE__ */ (0, vue.defineComponent)({
1604
1727
  onSubmit: (0, vue.withModifiers)(handleSubmit, ["prevent"])
1605
1728
  }, [(0, vue.renderSlot)(_ctx.$slots, "default", {
1606
1729
  isSubmitting: isSubmitting.value,
1730
+ isSubmitted: isSubmitted.value,
1731
+ submitCount: submitCount.value,
1607
1732
  isDisabled: props.isDisabled,
1608
- errors: errors.value
1733
+ isValid: isValid.value,
1734
+ isDirty: isDirty.value,
1735
+ isTouched: isTouched.value,
1736
+ errors: errors.value,
1737
+ getValues,
1738
+ setValue,
1739
+ setErrors,
1740
+ setError,
1741
+ clearErrors,
1742
+ trigger,
1743
+ reset
1609
1744
  })], 34);
1610
1745
  };
1611
1746
  }
@@ -1617,6 +1752,7 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1617
1752
  __name: "FormField",
1618
1753
  props: /* @__PURE__ */ (0, vue.mergeModels)({
1619
1754
  name: {},
1755
+ defaultValue: {},
1620
1756
  rules: {},
1621
1757
  validate: { type: Function },
1622
1758
  validationMode: {}
@@ -1630,6 +1766,8 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1630
1766
  const modelValue = (0, vue.useModel)(__props, "modelValue");
1631
1767
  const ctx = useFormInject();
1632
1768
  const localError = (0, vue.ref)(void 0);
1769
+ const touched = (0, vue.ref)(false);
1770
+ const dirty = (0, vue.ref)(props.defaultValue !== void 0 && modelValue.value !== props.defaultValue);
1633
1771
  const fieldError = (0, vue.computed)(() => ctx ? ctx.errors.value[props.name] : localError.value);
1634
1772
  const hasBeenInvalid = (0, vue.ref)(false);
1635
1773
  (0, vue.watch)(fieldError, (error) => {
@@ -1638,10 +1776,27 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1638
1776
  const isInvalid = (0, vue.computed)(() => !!fieldError.value);
1639
1777
  const isDisabled = (0, vue.computed)(() => ctx?.isDisabled.value ?? false);
1640
1778
  const validationMode = (0, vue.computed)(() => props.validationMode ?? ctx?.validationMode.value ?? "on-submit");
1779
+ (0, vue.watch)(modelValue, (val) => {
1780
+ dirty.value = val !== props.defaultValue;
1781
+ });
1782
+ function resetField() {
1783
+ modelValue.value = props.defaultValue;
1784
+ localError.value = void 0;
1785
+ touched.value = false;
1786
+ dirty.value = false;
1787
+ hasBeenInvalid.value = false;
1788
+ }
1641
1789
  (0, vue.onMounted)(() => {
1642
1790
  ctx?.registerField({
1643
1791
  name: props.name,
1644
1792
  getValue: () => modelValue.value,
1793
+ getDefaultValue: () => props.defaultValue,
1794
+ setValue: (val) => {
1795
+ modelValue.value = val;
1796
+ },
1797
+ reset: resetField,
1798
+ touched,
1799
+ dirty,
1645
1800
  rules: props.rules,
1646
1801
  validate: props.validate
1647
1802
  });
@@ -1650,7 +1805,8 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1650
1805
  ctx?.unregisterField(props.name);
1651
1806
  });
1652
1807
  async function triggerValidation(val) {
1653
- const error = await runValidation(val, props.rules, props.validate);
1808
+ const context = ctx ? { values: ctx.getValues() } : void 0;
1809
+ const error = await runValidation(val, props.rules, props.validate, context);
1654
1810
  if (ctx) {
1655
1811
  const next = { ...ctx.errors.value };
1656
1812
  if (error) next[props.name] = error;
@@ -1663,6 +1819,7 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1663
1819
  if (validationMode.value === "on-change" || hasBeenInvalid.value) await triggerValidation(val);
1664
1820
  }
1665
1821
  async function handleBlur() {
1822
+ touched.value = true;
1666
1823
  if (validationMode.value === "on-blur") await triggerValidation(modelValue.value);
1667
1824
  }
1668
1825
  const fieldProps = (0, vue.computed)(() => ({
@@ -1675,7 +1832,13 @@ var FormField_default = /* @__PURE__ */ (0, vue.defineComponent)({
1675
1832
  onBlur: handleBlur
1676
1833
  }));
1677
1834
  return (_ctx, _cache) => {
1678
- return (0, vue.renderSlot)(_ctx.$slots, "default", { fieldProps: fieldProps.value });
1835
+ return (0, vue.renderSlot)(_ctx.$slots, "default", {
1836
+ fieldProps: fieldProps.value,
1837
+ touched: touched.value,
1838
+ dirty: dirty.value,
1839
+ error: fieldError.value,
1840
+ isInvalid: isInvalid.value
1841
+ });
1679
1842
  };
1680
1843
  }
1681
1844
  });
@@ -15246,6 +15409,15 @@ var SelectContent_default = /* @__PURE__ */ (0, vue.defineComponent)({
15246
15409
  const props = __props;
15247
15410
  const ctx = useSelectInject();
15248
15411
  const rootContext = (0, reka_ui.injectSelectRootContext)();
15412
+ const justOpened = (0, vue.ref)(false);
15413
+ (0, vue.watch)(() => rootContext.open.value, (open) => {
15414
+ if (open) {
15415
+ justOpened.value = true;
15416
+ setTimeout(() => {
15417
+ justOpened.value = false;
15418
+ }, 100);
15419
+ }
15420
+ });
15249
15421
  return (_ctx, _cache) => {
15250
15422
  return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(reka_ui.SelectPortal), null, {
15251
15423
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(AnimatePresence_default), null, {
@@ -15255,7 +15427,7 @@ var SelectContent_default = /* @__PURE__ */ (0, vue.defineComponent)({
15255
15427
  "data-slot": "popover"
15256
15428
  }, {
15257
15429
  default: (0, vue.withCtx)(() => [(0, vue.withDirectives)((0, vue.createVNode)((0, vue.unref)(motion).div, {
15258
- class: (0, vue.normalizeClass)((0, vue.unref)(ctx).slots.value.popover()),
15430
+ class: (0, vue.normalizeClass)([(0, vue.unref)(ctx).slots.value.popover(), { "select__popover--opening": justOpened.value }]),
15259
15431
  animate: (0, vue.unref)(rootContext).open.value ? {
15260
15432
  opacity: 1,
15261
15433
  scale: 1