@leavepulse/ui 0.78.1 → 0.78.3

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 (147) 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-DRHoQtr-.js} +34 -17
  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 +19 -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/LpAppShell.vue +56 -18
  111. package/src/components/LpAutocomplete.vue +11 -5
  112. package/src/components/LpCheckbox.vue +8 -6
  113. package/src/components/LpColorPicker.vue +7 -4
  114. package/src/components/LpDatePicker.vue +8 -4
  115. package/src/components/LpDateRangePicker.vue +8 -4
  116. package/src/components/LpInput.vue +3 -4
  117. package/src/components/LpNumberField.vue +11 -6
  118. package/src/components/LpOtpInput.vue +8 -6
  119. package/src/components/LpPhoneInput.vue +11 -6
  120. package/src/components/LpRadioGroup.vue +9 -5
  121. package/src/components/LpRangeSlider.vue +8 -4
  122. package/src/components/LpRepeater.vue +16 -4
  123. package/src/components/LpSegmented.vue +8 -4
  124. package/src/components/LpSelect.vue +8 -7
  125. package/src/components/LpSlider.vue +8 -4
  126. package/src/components/LpSwitch.vue +8 -5
  127. package/src/components/LpTagsInput.vue +4 -3
  128. package/src/components/LpTextarea.vue +3 -2
  129. package/src/components/LpTimeField.vue +8 -6
  130. package/src/components/calendar.ts +2 -0
  131. package/src/composables/useField.ts +52 -0
  132. package/src/composables/useMergedClass.ts +11 -5
  133. package/dist/chunks/LpAddressInput-BSS49jpm.js +0 -393
  134. package/dist/chunks/LpAutocomplete-DkY6CSyD.js +0 -302
  135. package/dist/chunks/LpCheckbox-D6RuDW4X.js +0 -124
  136. package/dist/chunks/LpColorPicker-COHzV68R.js +0 -567
  137. package/dist/chunks/LpDatePicker-DwSDY0mt.js +0 -163
  138. package/dist/chunks/LpNumberField-Csg-1Zh_.js +0 -148
  139. package/dist/chunks/LpOtpInput-BRpLBbOD.js +0 -132
  140. package/dist/chunks/LpRadioGroup-BrazjLY_.js +0 -95
  141. package/dist/chunks/LpRangeSlider-fz61tzc-.js +0 -89
  142. package/dist/chunks/LpRepeater-BkJHSPI1.js +0 -180
  143. package/dist/chunks/LpSegmented-DbEJhbv-.js +0 -123
  144. package/dist/chunks/LpSelect-Y-iuSymW.js +0 -512
  145. package/dist/chunks/LpSlider-A4ixovgS.js +0 -68
  146. package/dist/chunks/LpSwitch-DnC2-0aV.js +0 -115
  147. 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-DRHoQtr-.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.3",
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>
@@ -47,8 +47,9 @@ export default { inheritAttrs: false }
47
47
  import { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, useSlots, watch } from "vue"
48
48
  import { easingToken, durationToken, prefersReducedMotion } from "../composables/easing"
49
49
  import { useLabels } from "../composables/useLpConfig"
50
+ import { useResizeObserver } from "../composables/useResizeObserver"
50
51
  import { useScrollMemory } from "../composables/scrollMemory"
51
- import { nodeWindow, useView, viewWindow } from "../composables/useView"
52
+ import { isHTMLElement, nodeWindow, useView, viewWindow } from "../composables/useView"
52
53
  import AppShellContextNav from "./AppShellContextNav.vue"
53
54
  import {
54
55
  contextNavItems,
@@ -129,6 +130,15 @@ const props = withDefaults(
129
130
  * `min-h-[calc(100dvh-4rem)]` or `fullBleed`. `"region"`: the shell is
130
131
  * the viewport and the page scrolls inside main. Read once: changing it
131
132
  * remounts the page.
133
+ *
134
+ * A page's own sticky parts keep clear of the shell's with two variables
135
+ * set inside it: `--lp-shell-top`, how much of the window's top the shell
136
+ * covers (the header, 0 while `headerCollapse` has it away, plus the
137
+ * sub-page row), and `--lp-shell-bottom`, how much of its foot (the bottom
138
+ * bar). Both change as those do, and are 0px in `"region"` and on a
139
+ * `fullBleed` page, where nothing of the shell's lies over the page:
140
+ * `position: sticky; top: var(--lp-shell-top)`. Keep the page's sticky
141
+ * layers under `--z-sticky`, the shell's.
132
142
  */
133
143
  scroll?: "document" | "region"
134
144
  /**
@@ -329,8 +339,8 @@ useScrollMemory(
329
339
  () => props.path,
330
340
  () => props.hash,
331
341
  "",
332
- // The sticky header covers the top of the window; a region starts below it.
333
- () => (documentScroll && !bleeding.value ? (headerEl.value?.offsetHeight ?? 0) : 0),
342
+ // The sticky header and sub-page row cover the top of the window; a region starts below them.
343
+ () => (documentScroll && !bleeding.value ? (headerEl.value?.offsetHeight ?? 0) + contextRowHeight.value : 0),
334
344
  )
335
345
  // The side region keeps its own place on the same address.
336
346
  useScrollMemory(
@@ -389,17 +399,19 @@ watch(bleeding, (bleed) => {
389
399
  void nextTick(() => view.scrollTo({ top, behavior: "instant" }))
390
400
  }
391
401
  })
392
- // The bottom bar's height, for the page's scrollbar to stop above it (0 where it is hidden).
402
+ /*
403
+ * What the shell's sticky bars cover of the window, for the page: the sub-page
404
+ * row's height (it sits under the header) and the bottom bar's (0 where hidden).
405
+ */
393
406
  const bottomBarEl = ref<{ $el: HTMLElement } | null>(null)
394
407
  const bottomBarHeight = ref(0)
395
- let bottomBarSize: ResizeObserver | undefined
396
- onMounted(() => {
397
- const el = bottomBarEl.value?.$el
398
- if (!el || el.nodeType !== 1) return
399
- bottomBarSize = new (nodeWindow(el).ResizeObserver)(() => (bottomBarHeight.value = el.offsetHeight))
400
- bottomBarSize.observe(el)
401
- })
402
- onBeforeUnmount(() => bottomBarSize?.disconnect())
408
+ useResizeObserver(
409
+ () => (bottomBarEl.value?.$el?.nodeType === 1 ? bottomBarEl.value.$el : null),
410
+ (_, el) => (bottomBarHeight.value = (el as HTMLElement).offsetHeight),
411
+ { immediate: true },
412
+ )
413
+ const contextRowEl = ref<HTMLElement | null>(null)
414
+ const contextRowHeight = ref(0)
403
415
 
404
416
  let releaseDocument: (() => void) | undefined
405
417
  onMounted(() => {
@@ -480,7 +492,7 @@ const asideClasses = computed(() =>
480
492
  const columnClass = computed(() => (hasAside.value ? "grid min-w-0 flex-1 grid-cols-[minmax(0,1fr)_auto]" : "flex min-w-0 flex-1 flex-col"))
481
493
  const columnStyle = computed(() => ({
482
494
  ...(hasAside.value ? { gridTemplateRows: `auto ${contextVisible.value ? "auto " : ""}minmax(0,1fr) auto` } : {}),
483
- ...(windowScrolls.value ? { "--lp-shell-top": shellTop.value } : {}),
495
+ ...shellVars.value,
484
496
  }))
485
497
  const spanClass = computed(() => (hasAside.value ? "col-span-2" : undefined))
486
498
 
@@ -520,6 +532,17 @@ const contextItems = computed(() => (props.adaptiveNav?.contextNav ? contextNavI
520
532
  const contextVisible = computed(
521
533
  () => (navMode.value === "bottom" || navMode.value === "drawer") && (contextItems.value.length > 0 || (!!slots["context-nav"] && !!props.adaptiveNav?.contextNav)),
522
534
  )
535
+ // The row is the app's own slot or the shell's, so it is found where it renders: right after the header.
536
+ watch(
537
+ [contextVisible, mounted],
538
+ () => {
539
+ const next = headerEl.value?.nextElementSibling
540
+ contextRowEl.value = contextVisible.value && isHTMLElement(next) && next !== mainEl.value ? next : null
541
+ if (!contextRowEl.value) contextRowHeight.value = 0
542
+ },
543
+ { flush: "post" },
544
+ )
545
+ useResizeObserver(contextRowEl, (_, el) => (contextRowHeight.value = (el as HTMLElement).offsetHeight), { immediate: true })
523
546
 
524
547
  function onSelect(item: SidebarItem) {
525
548
  emit("select", item)
@@ -564,12 +587,27 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
564
587
 
565
588
  /*
566
589
  * What stays in view while the window scrolls the page. The header sits on
567
- * top; the row of sub-pages and the aside sit under it, following it out
568
- * when it collapses (--lp-shell-top is how much of the header is showing).
590
+ * top; the row of sub-pages sits under it and follows it out when it
591
+ * collapses (--lp-shell-header is how much of the header is showing).
592
+ *
593
+ * Two variables are the page's to use (documented on `scroll`), and set in
594
+ * every mode, so `var(--lp-shell-top)` never needs a fallback:
595
+ * --lp-shell-top is how much of the window's top the shell covers (header
596
+ * plus sub-page row), --lp-shell-bottom how much of its foot (the bottom
597
+ * bar). Both are 0px where the page scrolls in its own region or is full bleed.
569
598
  */
570
599
  const STICKY = "sticky z-(--z-sticky)"
571
600
  const railClass = computed(() => (windowScrolls.value ? "sticky top-0 flex h-dvh shrink-0 self-start" : "contents"))
572
- const shellTop = computed(() => (headerHidden.value ? "0px" : headerHeight.value))
601
+ const shellHeader = computed(() => (headerHidden.value ? "0px" : headerHeight.value))
602
+ const shellVars = computed(() =>
603
+ windowScrolls.value
604
+ ? {
605
+ "--lp-shell-header": shellHeader.value,
606
+ "--lp-shell-top": `calc(${shellHeader.value} + ${contextRowHeight.value}px)`,
607
+ "--lp-shell-bottom": `${bottomBarHeight.value}px`,
608
+ }
609
+ : { "--lp-shell-header": "0px", "--lp-shell-top": "0px", "--lp-shell-bottom": "0px" },
610
+ )
573
611
  const BACK_TO_TOP_ABOVE_BAR: Record<NavBreakpoint, string> = {
574
612
  sm: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] sm:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
575
613
  md: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] md:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
@@ -725,7 +763,7 @@ const backToTopClass = computed(() =>
725
763
  <template v-if="contextVisible">
726
764
  <slot name="context-nav" :items="contextItems" :mode="navMode">
727
765
  <AppShellContextNav
728
- :class="[spanClass, windowScrolls && `${STICKY} top-(--lp-shell-top) transition-[top] duration-[var(--duration-medium)] ease-[var(--ease-settle)]`]"
766
+ :class="[spanClass, windowScrolls && `${STICKY} top-(--lp-shell-header) transition-[top] duration-[var(--duration-medium)] ease-[var(--ease-settle)]`]"
729
767
  :items="contextItems"
730
768
  :is-active="activeTest"
731
769
  :label="text.contextNav"
@@ -769,7 +807,7 @@ const backToTopClass = computed(() =>
769
807
  <slot name="aside" />
770
808
  </LpScrollArea>
771
809
  </aside>
772
- <LpPageScrollbar v-if="windowScrolls && pageScrollbar" top="var(--lp-shell-top)" :bottom="`${bottomBarHeight}px`" />
810
+ <LpPageScrollbar v-if="windowScrolls && pageScrollbar" top="var(--lp-shell-top)" bottom="var(--lp-shell-bottom)" />
773
811
  <LpBottomNav
774
812
  v-if="bottomNav"
775
813
  ref="bottomBarEl"
@@ -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>