@leavepulse/ui 0.78.1 → 0.78.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/chunks/{DropzoneLinkField-CLLhd3WB.js → DropzoneLinkField-CyE7TJ5f.js} +1 -1
  2. package/dist/chunks/LpAddressInput-ft8fQOGx.js +401 -0
  3. package/dist/chunks/{LpAppShell-BKbYCHkx.js → LpAppShell-DkvU6IBB.js} +1 -1
  4. package/dist/chunks/LpAutocomplete-CrZbd0uv.js +310 -0
  5. package/dist/chunks/LpCheckbox-CCWCwD0y.js +129 -0
  6. package/dist/chunks/{LpCodeDisplay-D3BUAhV1.js → LpCodeDisplay-D59uPwRb.js} +1 -1
  7. package/dist/chunks/LpColorPicker-BONURBFN.js +574 -0
  8. package/dist/chunks/LpDatePicker-C2AOtxgF.js +171 -0
  9. package/dist/chunks/{LpDateRangePicker-CNQXdTVv.js → LpDateRangePicker-CiXdIAyh.js} +43 -35
  10. package/dist/chunks/{LpFileTree-C-rJKzEQ.js → LpFileTree-CpNurwZp.js} +2 -2
  11. package/dist/chunks/{LpFileTreeNode-BgYn4U1J.js → LpFileTreeNode-DdF8Cq-s.js} +1 -1
  12. package/dist/chunks/{LpInput-D0O6dpuA.js → LpInput-CbI7z5fQ.js} +3 -4
  13. package/dist/chunks/{LpLogInspector-BdQlX6S-.js → LpLogInspector-CcSJSGan.js} +1 -1
  14. package/dist/chunks/{LpLogViewer-umCZBapN.js → LpLogViewer-CWu49Dko.js} +2 -2
  15. package/dist/chunks/{LpModalNav-gOi1Giz1.js → LpModalNav-DI3BW5ff.js} +1 -1
  16. package/dist/chunks/LpNumberField-C8LfUz_R.js +154 -0
  17. package/dist/chunks/LpOtpInput-B1X9l9no.js +140 -0
  18. package/dist/chunks/{LpPaletteTheme-BIXpZLGe.js → LpPaletteTheme-B-xuZiKK.js} +2 -2
  19. package/dist/chunks/{LpPasswordInput-D4HPhqfV.js → LpPasswordInput-Duc_3wPv.js} +1 -1
  20. package/dist/chunks/{LpPhoneInput-BSL7NX4z.js → LpPhoneInput-CctcRK9K.js} +124 -118
  21. package/dist/chunks/LpRadioGroup-DTM0nd9G.js +103 -0
  22. package/dist/chunks/LpRangeSlider-DJsEZXad.js +97 -0
  23. package/dist/chunks/LpRepeater-Czib3rmv.js +193 -0
  24. package/dist/chunks/{LpSecretField-B2roc4Iz.js → LpSecretField-BtlCk3IH.js} +1 -1
  25. package/dist/chunks/LpSegmented-sskrJKJJ.js +128 -0
  26. package/dist/chunks/LpSelect-JFZehOkd.js +515 -0
  27. package/dist/chunks/{LpSidebar-DDNJzb69.js → LpSidebar-CvRvVBTt.js} +1 -1
  28. package/dist/chunks/LpSlider-C4ilCtZX.js +76 -0
  29. package/dist/chunks/LpSwitch-DyAYTchz.js +122 -0
  30. package/dist/chunks/{LpTableFilter-B_XMOeAh.js → LpTableFilter-CJg5eIcV.js} +2 -2
  31. package/dist/chunks/{LpTagsInput-Dt0mteSj.js → LpTagsInput-CkNxpNYa.js} +4 -3
  32. package/dist/chunks/{LpTextarea-Co0b9PVx.js → LpTextarea-CFK_5QB8.js} +3 -2
  33. package/dist/chunks/{LpThemeStudio-ChU0_Ga8.js → LpThemeStudio-R-wohbCY.js} +2 -2
  34. package/dist/chunks/{LpThemeSwitcher-DmCZ21P_.js → LpThemeSwitcher-Bzy15MCP.js} +1 -1
  35. package/dist/chunks/LpTimeField-B5n0m8m0.js +115 -0
  36. package/dist/chunks/{LpTopologyCanvas-jqz1KCq2.js → LpTopologyCanvas-BNgw9RyZ.js} +2 -2
  37. package/dist/chunks/{LpWorkspaceSwitcher-BeNHCLd5.js → LpWorkspaceSwitcher-ugv-fyig.js} +1 -1
  38. package/dist/components/DropzoneLinkField.vue.js +1 -1
  39. package/dist/components/LpAddressInput.vue.d.ts +4 -0
  40. package/dist/components/LpAddressInput.vue.js +1 -1
  41. package/dist/components/LpAlert.vue.d.ts +3 -3
  42. package/dist/components/LpAppShell.vue.d.ts +1 -1
  43. package/dist/components/LpAppShell.vue.js +1 -1
  44. package/dist/components/LpAutocomplete.vue.d.ts +4 -0
  45. package/dist/components/LpAutocomplete.vue.js +1 -1
  46. package/dist/components/LpBadge.vue.d.ts +2 -2
  47. package/dist/components/LpChart.vue.d.ts +1 -1
  48. package/dist/components/LpCheckbox.vue.d.ts +4 -0
  49. package/dist/components/LpCheckbox.vue.js +1 -1
  50. package/dist/components/LpCodeDisplay.vue.js +1 -1
  51. package/dist/components/LpCollapse.vue.d.ts +1 -1
  52. package/dist/components/LpColorPicker.vue.d.ts +5 -3
  53. package/dist/components/LpColorPicker.vue.js +1 -1
  54. package/dist/components/LpDatePicker.vue.js +1 -1
  55. package/dist/components/LpDateRangePicker.vue.js +1 -1
  56. package/dist/components/LpDropzone.vue.js +1 -1
  57. package/dist/components/LpFileTree.vue.js +1 -1
  58. package/dist/components/LpFileTreeNode.vue.js +1 -1
  59. package/dist/components/LpImageEditor.vue.d.ts +1 -1
  60. package/dist/components/LpInput.vue.js +1 -1
  61. package/dist/components/LpLogInspector.vue.js +1 -1
  62. package/dist/components/LpLogViewer.vue.js +1 -1
  63. package/dist/components/LpModalNav.vue.js +1 -1
  64. package/dist/components/LpNumberField.vue.d.ts +4 -0
  65. package/dist/components/LpNumberField.vue.js +1 -1
  66. package/dist/components/LpOtpInput.vue.d.ts +4 -0
  67. package/dist/components/LpOtpInput.vue.js +1 -1
  68. package/dist/components/LpPaletteTheme.vue.js +1 -1
  69. package/dist/components/LpPasswordInput.vue.js +1 -1
  70. package/dist/components/LpPhoneInput.vue.d.ts +4 -0
  71. package/dist/components/LpPhoneInput.vue.js +1 -1
  72. package/dist/components/LpRadioGroup.vue.d.ts +4 -0
  73. package/dist/components/LpRadioGroup.vue.js +1 -1
  74. package/dist/components/LpRangeSlider.vue.d.ts +4 -0
  75. package/dist/components/LpRangeSlider.vue.js +1 -1
  76. package/dist/components/LpRepeater.vue.d.ts +2 -0
  77. package/dist/components/LpRepeater.vue.js +1 -1
  78. package/dist/components/LpScrollArea.vue.d.ts +1 -1
  79. package/dist/components/LpSecretField.vue.js +1 -1
  80. package/dist/components/LpSegmented.vue.d.ts +4 -0
  81. package/dist/components/LpSegmented.vue.js +1 -1
  82. package/dist/components/LpSelect.vue.d.ts +2 -0
  83. package/dist/components/LpSelect.vue.js +1 -1
  84. package/dist/components/LpShinyText.vue.d.ts +1 -1
  85. package/dist/components/LpSidebar.vue.d.ts +1 -1
  86. package/dist/components/LpSidebar.vue.js +1 -1
  87. package/dist/components/LpSlider.vue.d.ts +4 -0
  88. package/dist/components/LpSlider.vue.js +1 -1
  89. package/dist/components/LpSwitch.vue.d.ts +4 -0
  90. package/dist/components/LpSwitch.vue.js +1 -1
  91. package/dist/components/LpTable.vue.js +2 -2
  92. package/dist/components/LpTableFilter.vue.js +1 -1
  93. package/dist/components/LpTabs.vue.d.ts +1 -1
  94. package/dist/components/LpTagsInput.vue.js +1 -1
  95. package/dist/components/LpTextarea.vue.js +1 -1
  96. package/dist/components/LpThemeStudio.vue.js +1 -1
  97. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  98. package/dist/components/LpTimeField.vue.d.ts +4 -0
  99. package/dist/components/LpTimeField.vue.js +1 -1
  100. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  101. package/dist/components/LpWorkspaceSwitcher.vue.js +1 -1
  102. package/dist/components/calendar.d.ts +2 -0
  103. package/dist/composables/useField.d.ts +50 -0
  104. package/dist/composables/useField.js +31 -2
  105. package/dist/composables/useMergedClass.d.ts +6 -2
  106. package/dist/composables/useMergedClass.js +6 -6
  107. package/dist/index.js +34 -34
  108. package/package.json +1 -1
  109. package/src/components/LpAddressInput.vue +8 -4
  110. package/src/components/LpAutocomplete.vue +11 -5
  111. package/src/components/LpCheckbox.vue +8 -6
  112. package/src/components/LpColorPicker.vue +7 -4
  113. package/src/components/LpDatePicker.vue +8 -4
  114. package/src/components/LpDateRangePicker.vue +8 -4
  115. package/src/components/LpInput.vue +3 -4
  116. package/src/components/LpNumberField.vue +11 -6
  117. package/src/components/LpOtpInput.vue +8 -6
  118. package/src/components/LpPhoneInput.vue +11 -6
  119. package/src/components/LpRadioGroup.vue +9 -5
  120. package/src/components/LpRangeSlider.vue +8 -4
  121. package/src/components/LpRepeater.vue +16 -4
  122. package/src/components/LpSegmented.vue +8 -4
  123. package/src/components/LpSelect.vue +8 -7
  124. package/src/components/LpSlider.vue +8 -4
  125. package/src/components/LpSwitch.vue +8 -5
  126. package/src/components/LpTagsInput.vue +4 -3
  127. package/src/components/LpTextarea.vue +3 -2
  128. package/src/components/LpTimeField.vue +8 -6
  129. package/src/components/calendar.ts +2 -0
  130. package/src/composables/useField.ts +52 -0
  131. package/src/composables/useMergedClass.ts +11 -5
  132. package/dist/chunks/LpAddressInput-BSS49jpm.js +0 -393
  133. package/dist/chunks/LpAutocomplete-DkY6CSyD.js +0 -302
  134. package/dist/chunks/LpCheckbox-D6RuDW4X.js +0 -124
  135. package/dist/chunks/LpColorPicker-COHzV68R.js +0 -567
  136. package/dist/chunks/LpDatePicker-DwSDY0mt.js +0 -163
  137. package/dist/chunks/LpNumberField-Csg-1Zh_.js +0 -148
  138. package/dist/chunks/LpOtpInput-BRpLBbOD.js +0 -132
  139. package/dist/chunks/LpRadioGroup-BrazjLY_.js +0 -95
  140. package/dist/chunks/LpRangeSlider-fz61tzc-.js +0 -89
  141. package/dist/chunks/LpRepeater-BkJHSPI1.js +0 -180
  142. package/dist/chunks/LpSegmented-DbEJhbv-.js +0 -123
  143. package/dist/chunks/LpSelect-Y-iuSymW.js +0 -512
  144. package/dist/chunks/LpSlider-A4ixovgS.js +0 -68
  145. package/dist/chunks/LpSwitch-DnC2-0aV.js +0 -115
  146. package/dist/chunks/LpTimeField-DeOcKWJq.js +0 -110
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { _ } from "./chunks/LayoutCanvas-CZKOltfA.js";
2
- import { _ as _2 } from "./chunks/LpAddressInput-BSS49jpm.js";
2
+ import { _ as _2 } from "./chunks/LpAddressInput-ft8fQOGx.js";
3
3
  import { _ as _3 } from "./chunks/LpMapPicker-D5_YLLBC.js";
4
4
  import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
5
5
  import { _ as _4 } from "./chunks/LpActionBar-BGMk5KoG.js";
6
6
  import { _ as _5 } from "./chunks/LpAlert-CjvTZIKF.js";
7
- import { _ as _6 } from "./chunks/LpAppShell-BKbYCHkx.js";
8
- import { _ as _7 } from "./chunks/LpAutocomplete-DkY6CSyD.js";
7
+ import { _ as _6 } from "./chunks/LpAppShell-DkvU6IBB.js";
8
+ import { _ as _7 } from "./chunks/LpAutocomplete-CrZbd0uv.js";
9
9
  import { _ as _8 } from "./chunks/LpAvatar-cQVsNk6F.js";
10
10
  import { _ as _9 } from "./chunks/LpBadge-D5QQdDQ_.js";
11
11
  import { _ as _10 } from "./chunks/LpBreadcrumbs-CIIBsygI.js";
@@ -18,10 +18,10 @@ import { CHART_PALETTE, axisTicks, chartSummary, formatTick, markerIndex, niceSc
18
18
  import { chartView, lttbIndices, minMaxBuckets, panRange, slotOf, sourceOf, zoomRange } from "./components/chartWindow.js";
19
19
  import { useChartSync } from "./composables/useChartSync.js";
20
20
  import { createLinkedView, linkChart, linkLog, linkPipeline, linkTable, linkTopology, provideLinkedView, useLinkedView } from "./composables/useLinkedView.js";
21
- import { _ as _14 } from "./chunks/LpCheckbox-D6RuDW4X.js";
21
+ import { _ as _14 } from "./chunks/LpCheckbox-CCWCwD0y.js";
22
22
  import { _ as _15 } from "./chunks/LpCodeBlock-DBqy4RLd.js";
23
23
  import { tokenizeLines } from "./components/codeHighlight.js";
24
- import { _ as _16 } from "./chunks/LpColorPicker-COHzV68R.js";
24
+ import { _ as _16 } from "./chunks/LpColorPicker-BONURBFN.js";
25
25
  import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
26
26
  import { default as default3 } from "./components/LpCommandPalette.vue.js";
27
27
  import { applyQueryFilters, highlightParts, parseCommandQuery, parsePaletteQuery, rankCommandItems, searchCommandItems, swapCommandLayout } from "./components/commandSearch.js";
@@ -37,8 +37,8 @@ import { _ as _18 } from "./chunks/LpConfirmDialog-CnrmzkuN.js";
37
37
  import { _ as _19 } from "./chunks/LpConfirmHost-CwbObVGH.js";
38
38
  import { confirm, useConfirm } from "./components/confirm.js";
39
39
  import { _ as _20 } from "./chunks/LpContextMenu-Bx_IhQDS.js";
40
- import { _ as _21 } from "./chunks/LpDatePicker-DwSDY0mt.js";
41
- import { _ as _22 } from "./chunks/LpDateRangePicker-CNQXdTVv.js";
40
+ import { _ as _21 } from "./chunks/LpDatePicker-C2AOtxgF.js";
41
+ import { _ as _22 } from "./chunks/LpDateRangePicker-CiXdIAyh.js";
42
42
  import { _ as _23 } from "./chunks/LpRangeCalendar-BrqlGZzE.js";
43
43
  import { clampRange, dayAllowed, defaultDatePresets, defaultRangePresets, formatRange, normalizeRange, sameRange } from "./components/dateRange.js";
44
44
  import { _ as _24 } from "./chunks/LpDisclosure-DG7JCo-d.js";
@@ -47,7 +47,7 @@ import { _ as _26 } from "./chunks/LpDrawer-DXNQFpAA.js";
47
47
  import { _ as _27 } from "./chunks/LpDropdownMenu-CLzxIOgM.js";
48
48
  import { default as default9 } from "./components/LpDropzone.vue.js";
49
49
  import { _ as _28 } from "./chunks/LpEmptyState-DurPF001.js";
50
- import { _ as _29 } from "./chunks/LpFileTree-C-rJKzEQ.js";
50
+ import { _ as _29 } from "./chunks/LpFileTree-CpNurwZp.js";
51
51
  import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
52
52
  import { _ as _30 } from "./chunks/LpFieldNotice-DJ10cYIo.js";
53
53
  import { _ as _31 } from "./chunks/LpFormField-BKYn9dyP.js";
@@ -55,54 +55,54 @@ import { _ as _32 } from "./chunks/LpIcon-C6JpQ5td.js";
55
55
  import { i, r, a, b } from "./chunks/icons-CYfcpSDS.js";
56
56
  import { default as default10 } from "./components/LpImageEditor.vue.js";
57
57
  import { _ as _33 } from "./chunks/LpInfraNode-Bb5nbuFY.js";
58
- import { _ as _34 } from "./chunks/LpInput-D0O6dpuA.js";
58
+ import { _ as _34 } from "./chunks/LpInput-CbI7z5fQ.js";
59
59
  import { _ as _35 } from "./chunks/LpLightbox-CtDTQV01.js";
60
60
  import { fileNameOf } from "./components/lightbox.js";
61
61
  import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
62
- import { _ as _37 } from "./chunks/LpLogViewer-umCZBapN.js";
63
- import { _ as _38 } from "./chunks/LpLogInspector-BdQlX6S-.js";
62
+ import { _ as _37 } from "./chunks/LpLogViewer-CWu49Dko.js";
63
+ import { _ as _38 } from "./chunks/LpLogInspector-CcSJSGan.js";
64
64
  import { compilePattern, findIds, messageShape, structuredPayload, timeMs } from "./components/logTools.js";
65
65
  import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
66
66
  import { _ as _39 } from "./chunks/LpMediaGallery-BYEwySoF.js";
67
67
  import { _ as _40 } from "./chunks/LpModal-DDvrSAnf.js";
68
- import { _ as _41 } from "./chunks/LpModalNav-gOi1Giz1.js";
68
+ import { _ as _41 } from "./chunks/LpModalNav-DI3BW5ff.js";
69
69
  import { _ as _42 } from "./chunks/LpNotificationBell-DUbVyK6R.js";
70
- import { _ as _43 } from "./chunks/LpNumberField-Csg-1Zh_.js";
71
- import { _ as _44 } from "./chunks/LpTimeField-DeOcKWJq.js";
70
+ import { _ as _43 } from "./chunks/LpNumberField-C8LfUz_R.js";
71
+ import { _ as _44 } from "./chunks/LpTimeField-B5n0m8m0.js";
72
72
  import { _ as _45 } from "./chunks/LpNumberFlow-Vqj0tP7B.js";
73
- import { _ as _46 } from "./chunks/LpOtpInput-BRpLBbOD.js";
73
+ import { _ as _46 } from "./chunks/LpOtpInput-B1X9l9no.js";
74
74
  import { _ as _47 } from "./chunks/LpPagination-snQ020xQ.js";
75
- import { _ as _48 } from "./chunks/LpPasswordInput-D4HPhqfV.js";
75
+ import { _ as _48 } from "./chunks/LpPasswordInput-Duc_3wPv.js";
76
76
  import { _ as _49 } from "./chunks/LpPie-oVNHjsKD.js";
77
- import { _ as _50 } from "./chunks/LpPhoneInput-BSL7NX4z.js";
77
+ import { _ as _50 } from "./chunks/LpPhoneInput-CctcRK9K.js";
78
78
  import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
79
79
  import { _ as _51 } from "./chunks/LpPopover-BQSuxtai.js";
80
80
  import { _ as _52 } from "./chunks/LpProgress-D_MSjowb.js";
81
81
  import { _ as _53 } from "./chunks/LpRadio-CWA5Eb3M.js";
82
- import { _ as _54 } from "./chunks/LpRadioGroup-BrazjLY_.js";
82
+ import { _ as _54 } from "./chunks/LpRadioGroup-DTM0nd9G.js";
83
83
  import { _ as _55 } from "./chunks/LpRollingText-B54Pje7P.js";
84
84
  import { _ as _56 } from "./chunks/LpScrollArea-CqvwfZs2.js";
85
85
  import { _ as _57 } from "./chunks/LpPageScrollbar-D2O0xhJw.js";
86
- import { _ as _58 } from "./chunks/LpSegmented-DbEJhbv-.js";
86
+ import { _ as _58 } from "./chunks/LpSegmented-sskrJKJJ.js";
87
87
  import { _ as _59 } from "./chunks/LpSection-BfteipxU.js";
88
- import { _ as _60 } from "./chunks/LpSelect-Y-iuSymW.js";
88
+ import { _ as _60 } from "./chunks/LpSelect-JFZehOkd.js";
89
89
  import { fitChips, toggledValues } from "./components/select.js";
90
90
  import { _ as _61 } from "./chunks/LpServiceNode-Cln2ntdw.js";
91
91
  import { _ as _62 } from "./chunks/LpShift-DAgS_d2x.js";
92
92
  import { _ as _63 } from "./chunks/LpSwap-M7nFeW3C.js";
93
93
  import { _ as _64 } from "./chunks/LpHintExample-YzCXiSUp.js";
94
94
  import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
95
- import { _ as _65 } from "./chunks/LpSidebar-DDNJzb69.js";
95
+ import { _ as _65 } from "./chunks/LpSidebar-CvRvVBTt.js";
96
96
  import { _ as _66 } from "./chunks/LpContextSwitcher-1C1tExdl.js";
97
97
  import { _ as _67 } from "./chunks/LpSkeleton-BB6XIV-w.js";
98
- import { _ as _68 } from "./chunks/LpSlider-A4ixovgS.js";
99
- import { _ as _69 } from "./chunks/LpRangeSlider-fz61tzc-.js";
98
+ import { _ as _68 } from "./chunks/LpSlider-C4ilCtZX.js";
99
+ import { _ as _69 } from "./chunks/LpRangeSlider-DJsEZXad.js";
100
100
  import { _ as _70 } from "./chunks/LpVideoBackdrop-Ct4St4ZL.js";
101
101
  import { formatClipTime, isNativeLoop, planLoop, seamProgress, seamReached } from "./components/videoBackdrop.js";
102
102
  import { _ as _71 } from "./chunks/LpSparkline-CExIRDb3.js";
103
103
  import { _ as _72 } from "./chunks/LpStat-DPjc6_fX.js";
104
104
  import { _ as _73 } from "./chunks/LpStepper-DNnh7lCu.js";
105
- import { _ as _74 } from "./chunks/LpSwitch-DnC2-0aV.js";
105
+ import { _ as _74 } from "./chunks/LpSwitch-DyAYTchz.js";
106
106
  import { default as default12 } from "./components/LpTable.vue.js";
107
107
  import { compareValues } from "./components/tableSort.js";
108
108
  import { filterRows, showOnly, shownValues } from "./components/tableFilter.js";
@@ -111,10 +111,10 @@ import { resolveRowMenu } from "./components/tableRowMenu.js";
111
111
  import { _ as _75 } from "./chunks/LpTableOfContents-CKkWEK6R.js";
112
112
  import { default as default13 } from "./components/LpTabs.vue.js";
113
113
  import { _ as _76 } from "./chunks/LpBottomNav-zxLGGbjm.js";
114
- import { _ as _77 } from "./chunks/LpTagsInput-Dt0mteSj.js";
114
+ import { _ as _77 } from "./chunks/LpTagsInput-CkNxpNYa.js";
115
115
  import { addTags, splitTags } from "./components/tags.js";
116
- import { _ as _78 } from "./chunks/LpTextarea-Co0b9PVx.js";
117
- import { _ as _79 } from "./chunks/LpThemeSwitcher-DmCZ21P_.js";
116
+ import { _ as _78 } from "./chunks/LpTextarea-CFK_5QB8.js";
117
+ import { _ as _79 } from "./chunks/LpThemeSwitcher-Bzy15MCP.js";
118
118
  import { _ as _80 } from "./chunks/LpTilt-B7KHX1zH.js";
119
119
  import { _ as _81 } from "./chunks/LpToaster-Ct_ZOhCh.js";
120
120
  import { _ as _82 } from "./chunks/LpTooltip-Bz_rrq5S.js";
@@ -124,14 +124,14 @@ import { _ as _84 } from "./chunks/LpHintLayer-BeKRsRon.js";
124
124
  import { _ as _85 } from "./chunks/LpHints-qf3xYsza.js";
125
125
  import { HINT_SIGNALS, contextMenuTip, createHintSystem, dropzoneTip, hintKey, hintSummary, hotkeyTip, localHintStorage, noteDropzone, noteHotkeyTarget, paletteTip, provideHintSystem, runningHintSystem, useHintSystem } from "./composables/useHintSystem.js";
126
126
  import { _ as _86 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
127
- import { _ as _87 } from "./chunks/LpTopologyCanvas-jqz1KCq2.js";
127
+ import { _ as _87 } from "./chunks/LpTopologyCanvas-BNgw9RyZ.js";
128
128
  import { clusterGraph, diffTopology, findPath, layeredLayout, neighborhood, topologyToSvg } from "./components/topologyGraph.js";
129
129
  import { _ as _88 } from "./chunks/LpUptimeBar-BoxcCDVY.js";
130
130
  import { addLeaf, addTab, countBlocks, countLeaves, deserializeLayout, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, serializeLayout, setActiveTab } from "./layout/tree.js";
131
131
  import { blockTitle, defineBlocks } from "./layout/registry.js";
132
132
  import { layoutController, useLayout } from "./layout/useLayout.js";
133
133
  import { useWorkspaces } from "./layout/useWorkspaces.js";
134
- import { _ as _89 } from "./chunks/LpWorkspaceSwitcher-BeNHCLd5.js";
134
+ import { _ as _89 } from "./chunks/LpWorkspaceSwitcher-ugv-fyig.js";
135
135
  import { _ as _90 } from "./chunks/LpInspector-DO3fTCQ1.js";
136
136
  import { _ as _91 } from "./chunks/LpWindow-B8YSRVTH.js";
137
137
  import { WINDOW_DOCKS, clampRect, dockAt, dockedRect, isWindowRect, resizeRect, snapRect, useWindowLayer } from "./composables/windowing.js";
@@ -181,10 +181,10 @@ import { useZoomPan } from "./composables/useZoomPan.js";
181
181
  import { useToast } from "./composables/useToast.js";
182
182
  import { _ as _92 } from "./chunks/LpThemeProvider-XK6ZeWAE.js";
183
183
  import { _ as _93 } from "./chunks/LpFrame-Bv5Fphte.js";
184
- import { _ as _94 } from "./chunks/LpThemeStudio-ChU0_Ga8.js";
184
+ import { _ as _94 } from "./chunks/LpThemeStudio-R-wohbCY.js";
185
185
  import { _ as _95 } from "./chunks/LpThemeStudioSection-B7bt8Iyg.js";
186
186
  import { isInternalHref, resolveLink } from "./components/link.js";
187
- import { _ as _96 } from "./chunks/LpRepeater-BkJHSPI1.js";
187
+ import { _ as _96 } from "./chunks/LpRepeater-Czib3rmv.js";
188
188
  import { _ as _97 } from "./chunks/LpGauge-KZaQ_FDR.js";
189
189
  import { _ as _98 } from "./chunks/LpQuota-CgWPgdVt.js";
190
190
  import { _ as _99 } from "./chunks/LpStatus-DGJFwk5F.js";
@@ -205,11 +205,11 @@ import { useNow } from "./composables/useNow.js";
205
205
  import { _ as _105 } from "./chunks/LpCountdown-DVl7vXI1.js";
206
206
  import { DEFAULT_MILESTONES, DEFAULT_UNIT_LABELS, ceilToSecond, crossedMilestone, formatElapsed, formatTime, msToNextSecond, splitTime, timeParts } from "./components/timeSpan.js";
207
207
  import { _ as _106 } from "./chunks/LpCopyButton-sAMvWeLP.js";
208
- import { _ as _107 } from "./chunks/LpSecretField-B2roc4Iz.js";
208
+ import { _ as _107 } from "./chunks/LpSecretField-BtlCk3IH.js";
209
209
  import { _ as _108 } from "./chunks/LpDataList-CaVfsozH.js";
210
210
  import { _ as _109 } from "./chunks/LpEditable-DVT0Rh8F.js";
211
211
  import { _ as _110 } from "./chunks/LpTruncate-ellq9RYM.js";
212
- import { _ as _111 } from "./chunks/LpCodeDisplay-D3BUAhV1.js";
212
+ import { _ as _111 } from "./chunks/LpCodeDisplay-D59uPwRb.js";
213
213
  import { formatRemaining, groupCode, middleTruncate, normalizeCode } from "./components/fieldText.js";
214
214
  import { _ as _112 } from "./chunks/LpHoverCard-CHE9jAJG.js";
215
215
  import { _ as _113 } from "./chunks/LpIdenticon-Dbbr4fvt.js";
@@ -239,7 +239,7 @@ import { _ as _125 } from "./chunks/LpCommandScope-DRUvHiX7.js";
239
239
  import { createPaletteRegistry, mergePaletteCommands, usePaletteCommands, vPalette } from "./composables/usePaletteCommands.js";
240
240
  import { commandShortcuts, commandToHotkey, commandToMenuItem, commandToPalette, useCommands } from "./composables/useCommands.js";
241
241
  import { usePaletteTheme } from "./theme/palette.js";
242
- import { _ as _126 } from "./chunks/LpPaletteTheme-BIXpZLGe.js";
242
+ import { _ as _126 } from "./chunks/LpPaletteTheme-B-xuZiKK.js";
243
243
  export {
244
244
  CHART_PALETTE,
245
245
  DEFAULT_MASK_TOKENS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.78.1",
3
+ "version": "0.78.2",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -18,6 +18,7 @@ export default { inheritAttrs: false }
18
18
  * the picker is an async component, so the tile maths stays out of the bundle
19
19
  * of every form that never shows a map.
20
20
  */
21
+ import FieldWrapper from "./FieldWrapper.vue"
21
22
  import { computed, defineAsyncComponent, onMounted, ref, watch } from "vue"
22
23
  import { useAsyncTask } from "../composables/useAsyncTask"
23
24
  import {
@@ -41,7 +42,7 @@ import LpIcon from "./LpIcon.vue"
41
42
  import LpInput from "./LpInput.vue"
42
43
  import LpModal from "./LpModal.vue"
43
44
  import LpSelect from "./LpSelect.vue"
44
- import { useFieldControl, mergeDescribedBy } from "../composables/useField"
45
+ import { useOwnField, mergeDescribedBy } from "../composables/useField"
45
46
  import { useLabels } from "../composables/useLpConfig"
46
47
  import { useMergedAttrs } from "../composables/useMergedClass"
47
48
 
@@ -68,6 +69,8 @@ const props = withDefaults(
68
69
  disabled?: boolean
69
70
  /** Mark every part of the address invalid (also set by a surrounding LpFormField's error). */
70
71
  invalid?: boolean
72
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
73
+ error?: string
71
74
  size?: "sm" | "md" | "lg"
72
75
  /** Hide the map button when picking a point makes no sense. */
73
76
  hideMap?: boolean
@@ -289,15 +292,15 @@ function confirmPoint() {
289
292
  * every part: each inner field provides its own context, which would otherwise
290
293
  * hide the outer one from the controls.
291
294
  */
292
- const field = useFieldControl(() => ({ wrapped: false, invalid: props.invalid, disabled: props.disabled }))
295
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid, disabled: props.disabled }))
293
296
 
294
297
  // The group stacks its fields on a fixed gap that a tighter form has to close.
295
298
  const { class: rootClass, attrs: rest } = useMergedAttrs(
296
- "flex flex-col gap-3",
297
- )
299
+ "flex flex-col gap-3", () => ownAttrs())
298
300
  </script>
299
301
 
300
302
  <template>
303
+ <FieldWrapper v-bind="wrapper">
301
304
  <div
302
305
  role="group"
303
306
  :aria-labelledby="field.labelId"
@@ -428,4 +431,5 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
428
431
  </template>
429
432
  </LpModal>
430
433
  </div>
434
+ </FieldWrapper>
431
435
  </template>
@@ -10,6 +10,7 @@ export type AutocompleteLabels = {
10
10
  </script>
11
11
 
12
12
  <script setup lang="ts">
13
+ import FieldWrapper from "./FieldWrapper.vue"
13
14
  import IconCloseButton from "./IconCloseButton.vue"
14
15
  import { CONTROL_SIZE } from "./controlSize"
15
16
  import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
@@ -35,8 +36,8 @@ import {
35
36
  ComboboxRoot,
36
37
  ComboboxViewport,
37
38
  } from "reka-ui"
38
- import { computed, nextTick, ref, useId, watch } from "vue"
39
- import { useAttrsField, mergeDescribedBy } from "../composables/useField"
39
+ import { computed, nextTick, ref, useId, watch, useAttrs } from "vue"
40
+ import { useOwnField, mergeDescribedBy } from "../composables/useField"
40
41
  import { useInputFilter } from "../composables/useInputFilter"
41
42
  import { useLabels } from "../composables/useLpConfig"
42
43
  import { CLOSE_ICON, OPTION_ITEM, optionStagger, COMBOBOX_PANEL, POPOVER_PANEL } from "./dropdown"
@@ -64,6 +65,8 @@ const props = withDefaults(
64
65
  size?: "sm" | "md" | "lg"
65
66
  icon?: string
66
67
  invalid?: boolean
68
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
69
+ error?: string
67
70
  emptyText?: string
68
71
  loading?: boolean
69
72
  loadingText?: string
@@ -122,7 +125,8 @@ const inputAttrs = computed(() => {
122
125
  return rest
123
126
  })
124
127
 
125
- const { attrs, field } = useAttrsField(() => ({ invalid: props.invalid || isInvalid(props.modelValue), disabled: props.disabled }))
128
+ const attrs = useAttrs()
129
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid || isInvalid(props.modelValue), disabled: props.disabled }))
126
130
  const isInvalidState = computed(() => field.value.invalid)
127
131
  const labels = useLabels<AutocompleteLabels>(
128
132
  "autocomplete",
@@ -270,14 +274,15 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
270
274
  </script>
271
275
 
272
276
  <template>
277
+ <FieldWrapper v-bind="wrapper">
273
278
  <ComboboxRoot
274
279
  :open="open"
275
280
  :ignore-filter="true"
276
281
  :reset-search-term-on-blur="false"
277
282
  :reset-search-term-on-select="false"
278
283
  :disabled="field.disabled"
279
- :class="['relative', attrs.class]"
280
- :style="attrs.style as never"
284
+ :class="['relative', ownAttrs() ? attrs.class : undefined]"
285
+ :style="ownAttrs() ? (attrs.style as never) : undefined"
281
286
  @update:open="onOpenChange"
282
287
  >
283
288
  <ComboboxAnchor
@@ -410,4 +415,5 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
410
415
  </ComboboxContent>
411
416
  </ComboboxPortal>
412
417
  </ComboboxRoot>
418
+ </FieldWrapper>
413
419
  </template>
@@ -6,12 +6,13 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import FieldWrapper from "./FieldWrapper.vue"
9
10
  import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
10
11
  import { CheckboxIndicator, CheckboxRoot } from "reka-ui"
11
12
  import { computed, useId } from "vue"
12
13
  import LpIcon from "./LpIcon.vue"
13
14
  import LpLoader from "./LpLoader.vue"
14
- import { isAttrOn, mergeDescribedBy, useFieldControl } from "../composables/useField"
15
+ import { isAttrOn, mergeDescribedBy, useOwnField } from "../composables/useField"
15
16
  import { useOptimisticToggle } from "../composables/useOptimisticToggle"
16
17
  import { useMergedAttrs } from "../composables/useMergedClass"
17
18
 
@@ -22,6 +23,8 @@ const props = withDefaults(defineProps<{
22
23
  /** Mixed state (e.g. a "select all" with a partial selection). Shows a dash. */
23
24
  indeterminate?: boolean
24
25
  disabled?: boolean
26
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
27
+ error?: string
25
28
  label?: string
26
29
  /** Secondary line under the label, as on LpSwitch. */
27
30
  description?: string
@@ -67,8 +70,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
67
70
  [
68
71
  "group/check inline-flex cursor-pointer gap-2 text-sm text-ink",
69
72
  props.description ? "items-start" : "items-center",
70
- ].join(" "),
71
- )
73
+ ].join(" "), () => ownAttrs())
72
74
 
73
75
  /*
74
76
  * The box is the control, so what describes it (aria-*, name, title) goes to
@@ -89,9 +91,7 @@ const parts = computed(() => {
89
91
  return { label, control }
90
92
  })
91
93
 
92
- const field = useFieldControl(() => ({
93
- wrapped: false,
94
- id: props.id,
94
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, id: props.id,
95
95
  required: isAttrOn(rest.value.required),
96
96
  disabled: props.disabled,
97
97
  }))
@@ -104,6 +104,7 @@ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabl
104
104
  </script>
105
105
 
106
106
  <template>
107
+ <FieldWrapper v-bind="wrapper">
107
108
  <label
108
109
  :class="rootClass"
109
110
  v-bind="parts.label">
@@ -143,4 +144,5 @@ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabl
143
144
  </span>
144
145
  <slot v-else>{{ label }}</slot>
145
146
  </label>
147
+ </FieldWrapper>
146
148
  </template>
@@ -29,6 +29,7 @@
29
29
  * keeps the colours settled on in browser storage and offers them back above
30
30
  * the presets.
31
31
  */
32
+ import FieldWrapper from "./FieldWrapper.vue"
32
33
  import { CONTROL_SIZE } from "./controlSize"
33
34
  import { clamp } from "../composables/clamp"
34
35
  import {
@@ -41,7 +42,7 @@ import {
41
42
  import { computed, nextTick, ref, useAttrs, watch } from "vue"
42
43
  import { useKitStorage } from "../composables/usePersisted"
43
44
  import { prefersReducedMotion } from "../composables/easing"
44
- import { useFieldControl, mergeDescribedBy } from "../composables/useField"
45
+ import { useOwnField, mergeDescribedBy } from "../composables/useField"
45
46
  import {
46
47
  clampHsv,
47
48
  DEFAULT_SWATCHES,
@@ -103,6 +104,8 @@ const props = withDefaults(
103
104
  hideInput?: boolean
104
105
  disabled?: boolean
105
106
  invalid?: boolean
107
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
108
+ error?: string
106
109
  size?: "sm" | "md" | "lg"
107
110
  /** Trigger text beside the swatch. Defaults to the colour's own value. */
108
111
  label?: string
@@ -623,9 +626,7 @@ const menuItems = computed<ContextMenuItemDef[]>(() => {
623
626
  })
624
627
 
625
628
  const attrs = useAttrs()
626
- const field = useFieldControl(() => ({
627
- wrapped: false,
628
- invalid: props.invalid,
629
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid,
629
630
  disabled: props.disabled,
630
631
  }))
631
632
 
@@ -639,6 +640,7 @@ const guardOutside = useOutsideGuard()
639
640
  </script>
640
641
 
641
642
  <template>
643
+ <FieldWrapper v-bind="wrapper">
642
644
  <PopoverRoot v-model:open="open">
643
645
  <!-- reka supports chaining `as-child` triggers onto one element, but only
644
646
  when each link forwards the props down — and LpContextMenu is a wrapper
@@ -879,4 +881,5 @@ const guardOutside = useOutsideGuard()
879
881
  </PopoverContent>
880
882
  </PopoverPortal>
881
883
  </PopoverRoot>
884
+ </FieldWrapper>
882
885
  </template>
@@ -32,8 +32,9 @@ export interface DatePickerLabels extends Record<string, string> {
32
32
  * week") and, unlike the range picker's, are opt-in, so forms that already use
33
33
  * the picker keep the plain calendar they were laid out around.
34
34
  */
35
- import { computed, ref } from "vue"
36
- import { useAttrsField } from "../composables/useField"
35
+ import FieldWrapper from "./FieldWrapper.vue"
36
+ import { computed, ref, useAttrs } from "vue"
37
+ import { useOwnField } from "../composables/useField"
37
38
  import { useLocale } from "../composables/useLocale"
38
39
  import { useLabels } from "../composables/useLpConfig"
39
40
  import type { CalendarLabels, PickerFieldProps } from "./calendar"
@@ -131,7 +132,8 @@ function clear() {
131
132
  emit("update:modelValue", undefined)
132
133
  }
133
134
 
134
- const { attrs, field } = useAttrsField(() => ({ invalid: props.invalid, disabled: props.disabled }))
135
+ const attrs = useAttrs()
136
+ const { field, wrapper, controlAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid, disabled: props.disabled }))
135
137
  const text = useLabels<DatePickerLabels>(
136
138
  "datePicker",
137
139
  {
@@ -172,8 +174,9 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
172
174
  </script>
173
175
 
174
176
  <template>
177
+ <FieldWrapper v-bind="wrapper">
175
178
  <PickerField
176
- v-bind="attrs"
179
+ v-bind="controlAttrs"
177
180
  v-model:open="open"
178
181
  :field="field"
179
182
  :display="display"
@@ -221,4 +224,5 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
221
224
  </div>
222
225
  </div>
223
226
  </PickerField>
227
+ </FieldWrapper>
224
228
  </template>
@@ -9,8 +9,9 @@ export default { inheritAttrs: false }
9
9
  * Picking the second end or a preset fills the field and closes the popover.
10
10
  * Two months sit side by side where there is room, one on a phone.
11
11
  */
12
- import { computed, ref } from "vue"
13
- import { useAttrsField } from "../composables/useField"
12
+ import FieldWrapper from "./FieldWrapper.vue"
13
+ import { computed, ref, useAttrs } from "vue"
14
+ import { useOwnField } from "../composables/useField"
14
15
  import { useLocale } from "../composables/useLocale"
15
16
  import { useLabels } from "../composables/useLpConfig"
16
17
  import { useMediaQuery } from "../composables/useMediaQuery"
@@ -121,7 +122,8 @@ function presetFits(preset: DateRangePreset): boolean {
121
122
 
122
123
  const wide = useMediaQuery("(min-width: 640px)")
123
124
 
124
- const { attrs, field } = useAttrsField(() => ({ invalid: props.invalid, disabled: props.disabled }))
125
+ const attrs = useAttrs()
126
+ const { field, wrapper, controlAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid, disabled: props.disabled }))
125
127
  const showClear = computed(() => props.clearable && !!value.value && !field.value.disabled)
126
128
 
127
129
  const presetOptions = computed(() => presetList.value.map((preset) => ({
@@ -133,8 +135,9 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
133
135
  </script>
134
136
 
135
137
  <template>
138
+ <FieldWrapper v-bind="wrapper">
136
139
  <PickerField
137
- v-bind="attrs"
140
+ v-bind="controlAttrs"
138
141
  v-model:open="open"
139
142
  :field="field"
140
143
  :display="display"
@@ -163,4 +166,5 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
163
166
  @update:model-value="pick"
164
167
  />
165
168
  </PickerField>
169
+ </FieldWrapper>
166
170
  </template>
@@ -7,7 +7,7 @@ import { CONTROL_SIZE } from "./controlSize"
7
7
  import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
8
8
  import { tv, type VariantProps } from "tailwind-variants"
9
9
  import { computed, ref, useAttrs, useSlots } from "vue"
10
- import { fieldWrapperBinds, isAttrOn, mergeDescribedBy, useFieldControl } from "../composables/useField"
10
+ import { fieldWrapperBinds, isAttrOn, mergeDescribedBy, useField, useFieldControl, wrapsItself } from "../composables/useField"
11
11
  import { useLabels } from "../composables/useLpConfig"
12
12
  import { useInputFilter } from "../composables/useInputFilter"
13
13
  import { DEFAULT_MASK_TOKENS, useInputMask, type MaskSpec, type MaskTokens } from "../composables/useInputMask"
@@ -138,9 +138,8 @@ const slots = useSlots()
138
138
  const attrs = useAttrs()
139
139
  const hasLeading = computed(() => !!slots.leading || !!props.icon)
140
140
  const hasTrailing = computed(() => !!slots.trailing || showClear.value)
141
- const hasField = computed(
142
- () => !!props.label || !!props.hint || !!props.error,
143
- )
141
+ const outerFieldOf = useField()
142
+ const hasField = computed(() => wrapsItself(props, outerFieldOf))
144
143
  const field = useFieldControl(() => ({
145
144
  wrapped: hasField.value,
146
145
  hasMessage: !!props.error || !!props.hint,
@@ -6,6 +6,7 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import FieldWrapper from "./FieldWrapper.vue"
9
10
  import { CONTROL_SIZE } from "./controlSize"
10
11
  import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
11
12
  // Numeric input with stepper buttons (reka NumberField). Themed via tokens.
@@ -15,10 +16,10 @@ import {
15
16
  NumberFieldInput,
16
17
  NumberFieldRoot,
17
18
  } from "reka-ui"
18
- import { computed, useId } from "vue"
19
+ import { computed, useId, useAttrs } from "vue"
19
20
  import FieldLeading from "./FieldLeading.vue"
20
21
  import LpIcon from "./LpIcon.vue"
21
- import { focusLeft, useAttrsField, mergeDescribedBy } from "../composables/useField"
22
+ import { focusLeft, useOwnField, mergeDescribedBy } from "../composables/useField"
22
23
  import { useLabels } from "../composables/useLpConfig"
23
24
  import { useMergedClass } from "../composables/useMergedClass"
24
25
 
@@ -71,6 +72,8 @@ const props = withDefaults(defineProps<{
71
72
  /** A leading icon, as on LpInput; the `leading` slot replaces it. */
72
73
  icon?: string
73
74
  invalid?: boolean
75
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
76
+ error?: string
74
77
  /** Control height, matching LpInput. */
75
78
  size?: "sm" | "md" | "lg"
76
79
  labels?: Partial<NumberFieldLabels>
@@ -99,7 +102,8 @@ const text = useLabels<NumberFieldLabels>(
99
102
 
100
103
  const SIZE = CONTROL_SIZE
101
104
 
102
- const { attrs, field } = useAttrsField(() => ({ invalid: props.invalid, disabled: props.disabled }))
105
+ const attrs = useAttrs()
106
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid, disabled: props.disabled }))
103
107
  const describedBy = computed(
104
108
  () => mergeDescribedBy(attrs["aria-describedby"], field.value.describedBy, props.unit ? unitId : undefined),
105
109
  )
@@ -126,13 +130,13 @@ const rootClass = useMergedClass(() =>
126
130
  field.value.invalid
127
131
  ? "border-danger focus-within:border-danger focus-within:ring-danger-soft"
128
132
  : "border-line focus-within:border-brand focus-within:ring-ring",
129
- ].join(" "),
130
- )
133
+ ].join(" "), () => ownAttrs())
131
134
 
132
135
  usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.value.invalid })
133
136
  </script>
134
137
 
135
138
  <template>
139
+ <FieldWrapper v-bind="wrapper">
136
140
  <NumberFieldRoot
137
141
  :model-value="modelValue ?? undefined"
138
142
  :min="min"
@@ -149,7 +153,7 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
149
153
  :required="field.required"
150
154
  data-lp-ring-owner
151
155
  :class="rootClass"
152
- :style="attrs.style"
156
+ :style="ownAttrs() ? attrs.style : undefined"
153
157
  :name="typeof attrs.name === 'string' ? attrs.name : undefined"
154
158
  @update:model-value="(v) => emit('update:modelValue', Number.isNaN(v) ? null : (v ?? null))"
155
159
  @focusout="onFocusOut"
@@ -192,4 +196,5 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
192
196
  />
193
197
  </NumberFieldIncrement>
194
198
  </NumberFieldRoot>
199
+ </FieldWrapper>
195
200
  </template>
@@ -19,9 +19,10 @@ export default { inheritAttrs: false }
19
19
  * size's width and no further, and shrinks with the row when the container is
20
20
  * narrower, so eight cells fit a phone instead of running off its edge.
21
21
  */
22
+ import FieldWrapper from "./FieldWrapper.vue"
22
23
  import { PinInputInput, PinInputRoot } from "reka-ui"
23
24
  import { computed, ref, watch } from "vue"
24
- import { useFieldControl, mergeDescribedBy } from "../composables/useField"
25
+ import { useOwnField, mergeDescribedBy } from "../composables/useField"
25
26
  import { useMergedAttrs } from "../composables/useMergedClass"
26
27
  import { groupBreaks, joinCells, splitCode, upperCells, type OtpCells } from "./otp"
27
28
 
@@ -50,6 +51,8 @@ const props = withDefaults(
50
51
  group?: number | number[]
51
52
  /** Error state — tints the cells red (e.g. wrong code). */
52
53
  invalid?: boolean
54
+ /** A message under the control, as on LpInput: it marks it invalid and shows under it (what `form.field()` hands it). */
55
+ error?: string
53
56
  size?: "sm" | "md" | "lg"
54
57
  }>(),
55
58
  { length: 6, size: "md", alphanumeric: false, uppercase: undefined },
@@ -97,9 +100,7 @@ const cells = computed<string[]>({
97
100
  },
98
101
  })
99
102
 
100
- const field = useFieldControl(() => ({
101
- wrapped: false,
102
- invalid: props.invalid,
103
+ const { field, wrapper, ownAttrs } = useOwnField(() => ({ error: props.error, invalid: props.invalid,
103
104
  disabled: props.disabled,
104
105
  }))
105
106
 
@@ -144,11 +145,11 @@ const cellSize = {
144
145
  }
145
146
 
146
147
  const { class: rootClass, attrs: rest } = useMergedAttrs(
147
- "flex min-w-0 max-w-full items-center gap-1.5 sm:gap-2",
148
- )
148
+ "flex min-w-0 max-w-full items-center gap-1.5 sm:gap-2", () => ownAttrs())
149
149
  </script>
150
150
 
151
151
  <template>
152
+ <FieldWrapper v-bind="wrapper">
152
153
  <PinInputRoot
153
154
  ref="root"
154
155
  v-model="cells"
@@ -188,4 +189,5 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
188
189
  />
189
190
  </template>
190
191
  </PinInputRoot>
192
+ </FieldWrapper>
191
193
  </template>