ropav 0.0.10 → 0.0.12

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 (276) hide show
  1. package/README.md +9 -0
  2. package/dist/accordion.css +115 -111
  3. package/dist/accordion.js +60 -16
  4. package/dist/alert.css +110 -108
  5. package/dist/alert.js +48 -26
  6. package/dist/aspect-ratio.css +17 -15
  7. package/dist/aspect-ratio.js +20 -6
  8. package/dist/avatar.css +98 -96
  9. package/dist/avatar.js +27 -16
  10. package/dist/badge.css +95 -93
  11. package/dist/badge.js +29 -16
  12. package/dist/base.css +672 -671
  13. package/dist/button-group.css +39 -37
  14. package/dist/button-group.js +23 -12
  15. package/dist/button-link.css +160 -158
  16. package/dist/button-link.js +43 -24
  17. package/dist/button.css +160 -158
  18. package/dist/button.js +37 -19
  19. package/dist/card.css +109 -107
  20. package/dist/card.js +42 -17
  21. package/dist/checkbox.css +139 -137
  22. package/dist/checkbox.js +103 -33
  23. package/dist/collapse.css +29 -27
  24. package/dist/collapse.js +44 -10
  25. package/dist/color-input.css +137 -107
  26. package/dist/color-input.js +117 -30
  27. package/dist/color-picker.css +309 -303
  28. package/dist/color-picker.js +147 -54
  29. package/dist/color-picker2.js +9 -1
  30. package/dist/color-swatch.css +48 -46
  31. package/dist/color-swatch.js +15 -11
  32. package/dist/color-swatch2.js +4 -0
  33. package/dist/components/accordion/accordion-item.d.ts +13 -1
  34. package/dist/components/accordion/index.d.ts +2 -1
  35. package/dist/components/accordion/index.js +2 -2
  36. package/dist/components/accordion/types.d.ts +9 -4
  37. package/dist/components/alert/alert.d.ts +2 -2
  38. package/dist/components/alert/index.d.ts +2 -2
  39. package/dist/components/alert/index.js +2 -2
  40. package/dist/components/alert/types.d.ts +4 -1
  41. package/dist/components/aspect-ratio/index.d.ts +2 -1
  42. package/dist/components/aspect-ratio/index.js +2 -2
  43. package/dist/components/aspect-ratio/types.d.ts +4 -1
  44. package/dist/components/avatar/index.d.ts +2 -2
  45. package/dist/components/avatar/index.js +2 -2
  46. package/dist/components/avatar/types.d.ts +4 -1
  47. package/dist/components/badge/index.d.ts +2 -2
  48. package/dist/components/badge/index.js +2 -2
  49. package/dist/components/badge/types.d.ts +4 -1
  50. package/dist/components/button/index.d.ts +2 -1
  51. package/dist/components/button/index.js +2 -2
  52. package/dist/components/button/types.d.ts +4 -1
  53. package/dist/components/button-group/index.d.ts +2 -1
  54. package/dist/components/button-group/index.js +2 -2
  55. package/dist/components/button-group/types.d.ts +4 -1
  56. package/dist/components/button-link/index.d.ts +2 -1
  57. package/dist/components/button-link/index.js +2 -2
  58. package/dist/components/button-link/types.d.ts +4 -1
  59. package/dist/components/card/index.d.ts +2 -1
  60. package/dist/components/card/index.js +2 -2
  61. package/dist/components/card/types.d.ts +5 -1
  62. package/dist/components/checkbox/checkbox.d.ts +4 -1
  63. package/dist/components/checkbox/index.d.ts +2 -1
  64. package/dist/components/checkbox/index.js +2 -2
  65. package/dist/components/checkbox/types.d.ts +11 -2
  66. package/dist/components/checkbox/useCheckbox.d.ts +3 -1
  67. package/dist/components/collapse/collapse.d.ts +2 -2
  68. package/dist/components/collapse/index.d.ts +2 -1
  69. package/dist/components/collapse/index.js +2 -2
  70. package/dist/components/collapse/types.d.ts +9 -2
  71. package/dist/components/color-input/index.d.ts +2 -1
  72. package/dist/components/color-input/index.js +2 -2
  73. package/dist/components/color-input/types.d.ts +8 -2
  74. package/dist/components/color-input/useColorInput.d.ts +1 -1
  75. package/dist/components/color-input/useColorInputValue.d.ts +1 -1
  76. package/dist/components/color-picker/index.d.ts +2 -2
  77. package/dist/components/color-picker/index.js +2 -2
  78. package/dist/components/color-picker/types.d.ts +13 -1
  79. package/dist/components/color-swatch/index.d.ts +2 -1
  80. package/dist/components/color-swatch/index.js +2 -1
  81. package/dist/components/color-swatch/types.d.ts +4 -1
  82. package/dist/components/dialog/dialog-close.d.ts +21 -0
  83. package/dist/components/dialog/dialog-content.d.ts +32 -0
  84. package/dist/components/dialog/dialog-core.d.ts +27 -0
  85. package/dist/components/dialog/dialog-description.d.ts +21 -0
  86. package/dist/components/dialog/dialog-overlay.d.ts +21 -0
  87. package/dist/components/dialog/dialog-portal.d.ts +21 -0
  88. package/dist/components/dialog/dialog-root.d.ts +28 -0
  89. package/dist/components/dialog/dialog-title.d.ts +21 -0
  90. package/dist/components/dialog/dialog-trigger.d.ts +23 -0
  91. package/dist/components/dialog/index.d.ts +9 -0
  92. package/dist/components/dialog/index.js +2 -0
  93. package/dist/components/dialog/types.d.ts +61 -0
  94. package/dist/components/dropdown-menu/dropdown-menu-checkbox-item.d.ts +24 -0
  95. package/dist/components/dropdown-menu/dropdown-menu-content.d.ts +34 -0
  96. package/dist/components/dropdown-menu/dropdown-menu-context-trigger.d.ts +23 -0
  97. package/dist/components/dropdown-menu/dropdown-menu-item-indicator.d.ts +24 -0
  98. package/dist/components/dropdown-menu/dropdown-menu-item-row.d.ts +28 -0
  99. package/dist/components/dropdown-menu/dropdown-menu-item.d.ts +23 -0
  100. package/dist/components/dropdown-menu/dropdown-menu-items.d.ts +24 -22
  101. package/dist/components/dropdown-menu/dropdown-menu-label.d.ts +21 -0
  102. package/dist/components/dropdown-menu/dropdown-menu-outside.d.ts +3 -0
  103. package/dist/components/dropdown-menu/dropdown-menu-portal.d.ts +21 -0
  104. package/dist/components/dropdown-menu/dropdown-menu-primitive-core.d.ts +110 -0
  105. package/dist/components/dropdown-menu/dropdown-menu-primitives.d.ts +15 -0
  106. package/dist/components/dropdown-menu/dropdown-menu-radio-group.d.ts +25 -0
  107. package/dist/components/dropdown-menu/dropdown-menu-radio-item.d.ts +23 -0
  108. package/dist/components/dropdown-menu/dropdown-menu-root.d.ts +30 -0
  109. package/dist/components/dropdown-menu/dropdown-menu-separator.d.ts +19 -0
  110. package/dist/components/dropdown-menu/dropdown-menu-sub-content.d.ts +34 -0
  111. package/dist/components/dropdown-menu/dropdown-menu-sub-trigger.d.ts +28 -0
  112. package/dist/components/dropdown-menu/dropdown-menu-sub.d.ts +28 -0
  113. package/dist/components/dropdown-menu/dropdown-menu-trigger.d.ts +23 -0
  114. package/dist/components/dropdown-menu/dropdown-menu.d.ts +6 -3
  115. package/dist/components/dropdown-menu/index.d.ts +32 -1
  116. package/dist/components/dropdown-menu/index.js +2 -2
  117. package/dist/components/dropdown-menu/types.d.ts +145 -6
  118. package/dist/components/dropdown-menu/useDropdownMenu.d.ts +15 -3
  119. package/dist/components/dropdown-menu/useDropdownMenuDisclosure.d.ts +10 -3
  120. package/dist/components/dropdown-menu/useDropdownMenuDom.d.ts +2 -1
  121. package/dist/components/dropdown-menu/useDropdownMenuInteractions.d.ts +4 -4
  122. package/dist/components/dropdown-menu/useDropdownMenuPortalPosition.d.ts +19 -0
  123. package/dist/components/dropdown-menu/useDropdownMenuPrimitiveContent.d.ts +27 -0
  124. package/dist/components/dropdown-menu/useDropdownMenuRenderItems.d.ts +14 -2
  125. package/dist/components/field/index.d.ts +2 -1
  126. package/dist/components/field/index.js +2 -2
  127. package/dist/components/field/types.d.ts +4 -1
  128. package/dist/components/floating/index.d.ts +3 -0
  129. package/dist/components/floating/index.js +3 -0
  130. package/dist/components/floating/types.d.ts +105 -0
  131. package/dist/components/floating/useFloatingPosition.d.ts +15 -0
  132. package/dist/components/floating/useHoverDisclosure.d.ts +2 -0
  133. package/dist/components/focus-trap/focus-trap.d.ts +31 -0
  134. package/dist/components/focus-trap/index.d.ts +4 -0
  135. package/dist/components/focus-trap/index.js +3 -0
  136. package/dist/components/focus-trap/types.d.ts +41 -0
  137. package/dist/components/focus-trap/useFocusTrap.d.ts +2 -0
  138. package/dist/components/icon-button/index.d.ts +2 -1
  139. package/dist/components/icon-button/index.js +2 -1
  140. package/dist/components/icon-button/types.d.ts +4 -1
  141. package/dist/components/input/index.d.ts +2 -1
  142. package/dist/components/input/index.js +2 -1
  143. package/dist/components/input/input.d.ts +4 -1
  144. package/dist/components/input/types.d.ts +7 -2
  145. package/dist/components/modal/index.d.ts +2 -1
  146. package/dist/components/modal/index.js +2 -2
  147. package/dist/components/modal/modal.d.ts +3 -1
  148. package/dist/components/modal/types.d.ts +11 -1
  149. package/dist/components/modal/useModal.d.ts +7 -4
  150. package/dist/components/number-input/index.d.ts +2 -1
  151. package/dist/components/number-input/index.js +2 -2
  152. package/dist/components/number-input/types.d.ts +7 -2
  153. package/dist/components/number-input/useNumberInput.d.ts +2 -1
  154. package/dist/components/overlay/index.d.ts +2 -1
  155. package/dist/components/overlay/index.js +2 -1
  156. package/dist/components/overlay/types.d.ts +4 -1
  157. package/dist/components/popover/index.d.ts +2 -2
  158. package/dist/components/popover/index.js +2 -2
  159. package/dist/components/popover/popover.d.ts +2 -2
  160. package/dist/components/popover/types.d.ts +20 -11
  161. package/dist/components/popover/usePopover.d.ts +9 -1
  162. package/dist/components/progress/index.d.ts +2 -2
  163. package/dist/components/progress/index.js +2 -2
  164. package/dist/components/progress/types.d.ts +4 -1
  165. package/dist/components/radio/index.d.ts +2 -1
  166. package/dist/components/radio/index.js +2 -2
  167. package/dist/components/radio/radio.d.ts +8 -3
  168. package/dist/components/radio/types.d.ts +37 -4
  169. package/dist/components/radio/useRadio.d.ts +12 -4
  170. package/dist/components/select/index.d.ts +2 -1
  171. package/dist/components/select/index.js +2 -2
  172. package/dist/components/select/select.d.ts +4 -1
  173. package/dist/components/select/types.d.ts +10 -2
  174. package/dist/components/select/useSelect.d.ts +3 -1
  175. package/dist/components/slider/index.d.ts +2 -2
  176. package/dist/components/slider/index.js +2 -2
  177. package/dist/components/slider/range-slider-tooltip.d.ts +3 -0
  178. package/dist/components/slider/range-slider.d.ts +7 -4
  179. package/dist/components/slider/slider.d.ts +4 -1
  180. package/dist/components/slider/sliderCore.d.ts +4 -4
  181. package/dist/components/slider/types.d.ts +22 -4
  182. package/dist/components/slider/useRangeSlider.d.ts +2 -2
  183. package/dist/components/slider/useSlider.d.ts +2 -2
  184. package/dist/components/switch/index.d.ts +2 -1
  185. package/dist/components/switch/index.js +2 -2
  186. package/dist/components/switch/switch.d.ts +4 -1
  187. package/dist/components/switch/types.d.ts +11 -2
  188. package/dist/components/switch/useSwitch.d.ts +3 -1
  189. package/dist/components/tabs/index.d.ts +2 -1
  190. package/dist/components/tabs/index.js +2 -2
  191. package/dist/components/tabs/types.d.ts +13 -4
  192. package/dist/components/teleport-provider/index.d.ts +3 -0
  193. package/dist/components/teleport-provider/index.js +3 -0
  194. package/dist/components/teleport-provider/teleport-provider.d.ts +21 -0
  195. package/dist/components/teleport-provider/types.d.ts +4 -0
  196. package/dist/components/teleport-provider/useTeleportTarget.d.ts +6 -0
  197. package/dist/components/textarea/index.d.ts +2 -1
  198. package/dist/components/textarea/index.js +2 -2
  199. package/dist/components/textarea/textarea.d.ts +4 -1
  200. package/dist/components/textarea/types.d.ts +10 -2
  201. package/dist/components/textarea/useTextarea.d.ts +2 -1
  202. package/dist/components/toast/index.d.ts +3 -2
  203. package/dist/components/toast/index.js +2 -2
  204. package/dist/components/toast/toast-store.d.ts +2 -0
  205. package/dist/components/toast/toast.d.ts +2 -2
  206. package/dist/components/toast/types.d.ts +20 -10
  207. package/dist/components/toast/useToast.d.ts +2 -2
  208. package/dist/components/tooltip/index.d.ts +2 -1
  209. package/dist/components/tooltip/index.js +2 -1
  210. package/dist/components/tooltip/tooltip.d.ts +2 -2
  211. package/dist/components/tooltip/types.d.ts +13 -12
  212. package/dist/components/tooltip/useTooltip.d.ts +12 -2
  213. package/dist/composables/useOverlayLayer.d.ts +32 -0
  214. package/dist/dialog.js +510 -0
  215. package/dist/dropdown-menu.css +191 -108
  216. package/dist/dropdown-menu.js +1954 -198
  217. package/dist/field.css +41 -39
  218. package/dist/field.js +40 -16
  219. package/dist/floating.js +403 -0
  220. package/dist/focus-trap.js +80 -0
  221. package/dist/icon-button.css +193 -189
  222. package/dist/icon-button.js +23 -18
  223. package/dist/icon-button2.js +8 -0
  224. package/dist/index.d.ts +5 -0
  225. package/dist/index.js +39 -32
  226. package/dist/input.css +122 -120
  227. package/dist/input.js +63 -40
  228. package/dist/input2.js +9 -0
  229. package/dist/legacy-unlayered.css +5382 -0
  230. package/dist/modal.css +129 -127
  231. package/dist/modal.js +182 -281
  232. package/dist/number-input.css +87 -85
  233. package/dist/number-input.js +98 -26
  234. package/dist/overlay.css +26 -24
  235. package/dist/overlay.js +17 -9
  236. package/dist/overlay2.js +4 -0
  237. package/dist/popover.css +140 -107
  238. package/dist/popover.js +276 -196
  239. package/dist/popover2.js +6 -1
  240. package/dist/progress.css +101 -99
  241. package/dist/progress.js +50 -28
  242. package/dist/radio.css +114 -105
  243. package/dist/radio.js +237 -61
  244. package/dist/select.css +255 -242
  245. package/dist/select.js +257 -94
  246. package/dist/slider.css +1090 -1031
  247. package/dist/slider.js +443 -175
  248. package/dist/styles-api.d.ts +22 -0
  249. package/dist/styles-api.js +49 -0
  250. package/dist/switch.css +120 -108
  251. package/dist/switch.js +112 -38
  252. package/dist/tabs.css +286 -278
  253. package/dist/tabs.js +60 -21
  254. package/dist/teleport-provider.js +15 -0
  255. package/dist/textarea.css +132 -130
  256. package/dist/textarea.js +83 -31
  257. package/dist/toast.css +229 -225
  258. package/dist/toast.js +189 -118
  259. package/dist/tooltip.css +61 -106
  260. package/dist/tooltip.js +184 -228
  261. package/dist/tooltip2.js +8 -0
  262. package/dist/useControlState.js +4 -0
  263. package/dist/useFloatingPosition.js +1317 -0
  264. package/dist/useFocusTrap.js +130 -0
  265. package/dist/useFormControl.js +107 -0
  266. package/dist/useOverlayLayer.js +262 -0
  267. package/dist/useTeleportTarget.js +40 -0
  268. package/docs/public-floating-api.md +148 -0
  269. package/docs/public-styles-api.md +134 -0
  270. package/docs/public-tokens.md +545 -0
  271. package/package.json +37 -9
  272. package/src/styles/_tokens.scss +33 -28
  273. package/src/styles/_utilities.scss +11 -9
  274. package/src/styles/styles-manifest.json +4125 -0
  275. package/dist/rafScheduler.js +0 -34
  276. package/dist/useClickOutside.js +0 -24
@@ -0,0 +1,130 @@
1
+ import { onBeforeUnmount, readonly, ref, shallowRef, toValue, watch } from "vue";
2
+ import { createFocusTrap } from "focus-trap";
3
+ //#region src/components/focus-trap/useFocusTrap.ts
4
+ function hasContainers(containers) {
5
+ return Array.isArray(containers) ? containers.length > 0 : Boolean(containers);
6
+ }
7
+ function useFocusTrap(target, options = {}) {
8
+ const focusTrap = shallowRef(null);
9
+ const isActive = ref(false);
10
+ const isPaused = ref(false);
11
+ let shouldActivate = Boolean(options.immediate);
12
+ let shouldPause = false;
13
+ function syncState(trap) {
14
+ isActive.value = trap.active;
15
+ isPaused.value = trap.paused;
16
+ }
17
+ function createTrap(containers) {
18
+ const { immediate: _immediate, ...focusTrapOptions } = options;
19
+ const { onActivate, onDeactivate, onPause, onUnpause, onPostActivate, onPostDeactivate, onPostPause, onPostUnpause } = focusTrapOptions;
20
+ const trap = createFocusTrap(containers, {
21
+ ...focusTrapOptions,
22
+ onActivate(parameters) {
23
+ syncState(parameters.trap);
24
+ onActivate?.(parameters);
25
+ },
26
+ onPostActivate(parameters) {
27
+ syncState(parameters.trap);
28
+ onPostActivate?.(parameters);
29
+ },
30
+ onDeactivate(parameters) {
31
+ syncState(parameters.trap);
32
+ onDeactivate?.(parameters);
33
+ },
34
+ onPostDeactivate(parameters) {
35
+ syncState(parameters.trap);
36
+ onPostDeactivate?.(parameters);
37
+ },
38
+ onPause(parameters) {
39
+ syncState(parameters.trap);
40
+ onPause?.(parameters);
41
+ },
42
+ onPostPause(parameters) {
43
+ syncState(parameters.trap);
44
+ onPostPause?.(parameters);
45
+ },
46
+ onUnpause(parameters) {
47
+ syncState(parameters.trap);
48
+ onUnpause?.(parameters);
49
+ },
50
+ onPostUnpause(parameters) {
51
+ syncState(parameters.trap);
52
+ onPostUnpause?.(parameters);
53
+ }
54
+ });
55
+ focusTrap.value = trap;
56
+ return trap;
57
+ }
58
+ function activate(activateOptions) {
59
+ shouldActivate = true;
60
+ shouldPause = false;
61
+ const trap = focusTrap.value;
62
+ if (!trap) return;
63
+ trap.activate(activateOptions);
64
+ syncState(trap);
65
+ }
66
+ function deactivate(deactivateOptions) {
67
+ shouldActivate = false;
68
+ shouldPause = false;
69
+ const trap = focusTrap.value;
70
+ if (!trap) return;
71
+ trap.deactivate(deactivateOptions);
72
+ syncState(trap);
73
+ }
74
+ function pause(pauseOptions) {
75
+ shouldPause = true;
76
+ const trap = focusTrap.value;
77
+ if (!trap) return;
78
+ trap.pause(pauseOptions);
79
+ syncState(trap);
80
+ }
81
+ function unpause(unpauseOptions) {
82
+ shouldPause = false;
83
+ const trap = focusTrap.value;
84
+ if (!trap) return;
85
+ trap.unpause(unpauseOptions);
86
+ syncState(trap);
87
+ }
88
+ function updateContainerElements(containers) {
89
+ const trap = focusTrap.value ?? createTrap(containers);
90
+ trap.updateContainerElements(containers);
91
+ syncState(trap);
92
+ }
93
+ watch(() => toValue(target), (containers) => {
94
+ if (!hasContainers(containers)) {
95
+ focusTrap.value?.deactivate({ returnFocus: false });
96
+ focusTrap.value = null;
97
+ isActive.value = false;
98
+ isPaused.value = false;
99
+ return;
100
+ }
101
+ const trap = focusTrap.value ?? createTrap(containers);
102
+ trap.updateContainerElements(containers);
103
+ if (shouldActivate && !trap.active) trap.activate();
104
+ if (shouldPause && trap.active && !trap.paused) trap.pause();
105
+ syncState(trap);
106
+ }, {
107
+ flush: "post",
108
+ immediate: true
109
+ });
110
+ onBeforeUnmount(() => {
111
+ shouldActivate = false;
112
+ shouldPause = false;
113
+ focusTrap.value?.deactivate();
114
+ focusTrap.value = null;
115
+ isActive.value = false;
116
+ isPaused.value = false;
117
+ });
118
+ return {
119
+ focusTrap,
120
+ isActive: readonly(isActive),
121
+ isPaused: readonly(isPaused),
122
+ activate,
123
+ deactivate,
124
+ pause,
125
+ unpause,
126
+ updateContainerElements
127
+ };
128
+ }
129
+ //#endregion
130
+ export { useFocusTrap as t };
@@ -0,0 +1,107 @@
1
+ import { computed, inject, provide, shallowRef, watch, watchEffect } from "vue";
2
+ //#region src/composables/useControllableValue.ts
3
+ function useControllableValue(options) {
4
+ const initialValue = options.defaultValue();
5
+ const uncontrolledValue = shallowRef(initialValue);
6
+ const isControlled = computed(() => options.modelValue() !== void 0);
7
+ watch(options.modelValue, (value) => {
8
+ if (value !== void 0) uncontrolledValue.value = value;
9
+ }, { immediate: true });
10
+ const value = computed(() => options.modelValue() ?? uncontrolledValue.value);
11
+ function setValue(nextValue) {
12
+ if (!isControlled.value) uncontrolledValue.value = nextValue;
13
+ options.onChange(nextValue);
14
+ }
15
+ function resetValue(nextValue = initialValue) {
16
+ if (!isControlled.value) uncontrolledValue.value = nextValue;
17
+ }
18
+ return {
19
+ initialValue,
20
+ isControlled,
21
+ value,
22
+ setValue,
23
+ resetValue
24
+ };
25
+ }
26
+ //#endregion
27
+ //#region src/composables/useFormControl.ts
28
+ var nestedFormControlOwnerKey = Symbol("nestedFormControlOwner");
29
+ function provideNestedFormControlOwner() {
30
+ let claimed = false;
31
+ provide(nestedFormControlOwnerKey, () => {
32
+ if (claimed) return false;
33
+ claimed = true;
34
+ return true;
35
+ });
36
+ }
37
+ function claimNestedFormControlOwner() {
38
+ return inject(nestedFormControlOwnerKey, void 0)?.() ?? false;
39
+ }
40
+ function getElements(options) {
41
+ return options.elements().filter((element) => Boolean(element));
42
+ }
43
+ function useFormControl(options) {
44
+ const initialized = /* @__PURE__ */ new WeakSet();
45
+ watchEffect(() => {
46
+ const elements = getElements(options);
47
+ for (const [index, element] of elements.entries()) {
48
+ if (!initialized.has(element)) {
49
+ options.initializeDefault?.(element, index);
50
+ initialized.add(element);
51
+ }
52
+ element.setCustomValidity(options.validationMessage?.(element, index, elements) ?? "");
53
+ }
54
+ }, { flush: "post" });
55
+ watchEffect((onCleanup) => {
56
+ const documents = new Set(getElements(options).map((element) => element.ownerDocument));
57
+ if (documents.size === 0) return;
58
+ function onReset(event) {
59
+ const form = event.target;
60
+ if (!(form instanceof HTMLFormElement)) return;
61
+ const elements = getElements(options).filter((element) => element.form === form);
62
+ if (elements.length === 0) return;
63
+ queueMicrotask(() => {
64
+ if (options.isControlled()) options.syncControlledValue(elements);
65
+ else options.readResetValue(elements);
66
+ });
67
+ }
68
+ for (const document of documents) document.addEventListener("reset", onReset, true);
69
+ onCleanup(() => {
70
+ for (const document of documents) document.removeEventListener("reset", onReset, true);
71
+ });
72
+ }, { flush: "post" });
73
+ }
74
+ function useTextFormControl(element, controllable, validationMessage) {
75
+ useFormControl({
76
+ elements: () => [element()],
77
+ isControlled: () => controllable.isControlled.value,
78
+ initializeDefault(control) {
79
+ control.defaultValue = controllable.initialValue;
80
+ },
81
+ validationMessage,
82
+ readResetValue([control]) {
83
+ controllable.resetValue(control.value);
84
+ },
85
+ syncControlledValue([control]) {
86
+ control.value = controllable.value.value;
87
+ }
88
+ });
89
+ }
90
+ function useCheckedFormControl(element, controllable, validationMessage) {
91
+ useFormControl({
92
+ elements: () => [element()],
93
+ isControlled: () => controllable.isControlled.value,
94
+ initializeDefault(control) {
95
+ control.defaultChecked = controllable.initialValue;
96
+ },
97
+ validationMessage,
98
+ readResetValue([control]) {
99
+ controllable.resetValue(control.checked);
100
+ },
101
+ syncControlledValue([control]) {
102
+ control.checked = controllable.value.value;
103
+ }
104
+ });
105
+ }
106
+ //#endregion
107
+ export { useTextFormControl as a, useFormControl as i, provideNestedFormControlOwner as n, useControllableValue as o, useCheckedFormControl as r, claimNestedFormControlOwner as t };
@@ -0,0 +1,262 @@
1
+ import { computed, inject, onBeforeUnmount, provide, readonly, ref, shallowRef, toValue, watch } from "vue";
2
+ //#region src/composables/useOverlayLayer.ts
3
+ var overlayLayerKey = Symbol("overlay-layer");
4
+ var documentStates = /* @__PURE__ */ new WeakMap();
5
+ var layerMetadata = /* @__PURE__ */ new WeakMap();
6
+ function createState() {
7
+ return {
8
+ layers: [],
9
+ inertSnapshots: /* @__PURE__ */ new Map(),
10
+ originalBodyOverflow: "",
11
+ scrollLocked: false,
12
+ observer: null,
13
+ syncQueued: false
14
+ };
15
+ }
16
+ function getState(document) {
17
+ const existing = documentStates.get(document);
18
+ if (existing) return existing;
19
+ const state = createState();
20
+ documentStates.set(document, state);
21
+ return state;
22
+ }
23
+ function isDescendantLayer(layer, ancestor) {
24
+ let parent = layerMetadata.get(layer)?.parent ?? null;
25
+ while (parent) {
26
+ if (parent === ancestor) return true;
27
+ parent = layerMetadata.get(parent)?.parent ?? null;
28
+ }
29
+ return false;
30
+ }
31
+ function syncLayerZIndices(state) {
32
+ let highestZIndex = Number.NEGATIVE_INFINITY;
33
+ for (const layer of state.layers) {
34
+ const metadata = layerMetadata.get(layer);
35
+ if (!metadata) continue;
36
+ const zIndex = Math.max(metadata.baseZIndex, highestZIndex + 2);
37
+ metadata.setZIndex(zIndex);
38
+ highestZIndex = zIndex;
39
+ }
40
+ }
41
+ function isEventWithinElement(event, element) {
42
+ const path = event.composedPath();
43
+ if (path.length > 0) return path.some((entry) => entry === element || typeof Node !== "undefined" && entry instanceof Node && element.contains(entry));
44
+ return typeof Node !== "undefined" && event.target instanceof Node && element.contains(event.target);
45
+ }
46
+ function restoreInertBackground(state) {
47
+ for (const [element, snapshot] of state.inertSnapshots) {
48
+ element.inert = snapshot.inert;
49
+ if (snapshot.ariaHidden == null) element.removeAttribute("aria-hidden");
50
+ else element.setAttribute("aria-hidden", snapshot.ariaHidden);
51
+ }
52
+ state.inertSnapshots.clear();
53
+ }
54
+ function inertElement(state, element) {
55
+ if (!state.inertSnapshots.has(element)) state.inertSnapshots.set(element, {
56
+ ariaHidden: element.getAttribute("aria-hidden"),
57
+ inert: Boolean(element.inert)
58
+ });
59
+ element.inert = true;
60
+ element.setAttribute("aria-hidden", "true");
61
+ }
62
+ function inertUnprotectedBranches(state, parent, protectedRoots) {
63
+ for (const child of parent.children) {
64
+ if (!(child instanceof HTMLElement)) continue;
65
+ if (!protectedRoots.some((root) => child === root || child.contains(root))) {
66
+ inertElement(state, child);
67
+ continue;
68
+ }
69
+ if (!protectedRoots.includes(child)) inertUnprotectedBranches(state, child, protectedRoots);
70
+ }
71
+ }
72
+ function stopObserver(state) {
73
+ state.observer?.disconnect();
74
+ state.observer = null;
75
+ state.syncQueued = false;
76
+ }
77
+ function unlockScroll(document, state) {
78
+ if (!state.scrollLocked) return;
79
+ document.body.style.overflow = state.originalBodyOverflow;
80
+ state.scrollLocked = false;
81
+ }
82
+ function queueModalEffects(document, state) {
83
+ if (state.syncQueued) return;
84
+ state.syncQueued = true;
85
+ queueMicrotask(() => {
86
+ state.syncQueued = false;
87
+ syncModalEffects(document, state);
88
+ });
89
+ }
90
+ function startObserver(document, state) {
91
+ if (state.observer || typeof MutationObserver === "undefined") return;
92
+ state.observer = new MutationObserver(() => queueModalEffects(document, state));
93
+ state.observer.observe(document.body, {
94
+ childList: true,
95
+ subtree: true
96
+ });
97
+ }
98
+ function syncModalEffects(document, state) {
99
+ restoreInertBackground(state);
100
+ let modalIndex = -1;
101
+ for (let index = state.layers.length - 1; index >= 0; index -= 1) {
102
+ const layer = state.layers[index];
103
+ if (layer?.modalEffects && layer.modal.value) {
104
+ modalIndex = index;
105
+ break;
106
+ }
107
+ }
108
+ const shouldLock = state.layers.some((layer) => layer.modalEffects && layer.modal.value && layer.preventScroll.value);
109
+ if (shouldLock && !state.scrollLocked) {
110
+ state.originalBodyOverflow = document.body.style.overflow;
111
+ document.body.style.overflow = "hidden";
112
+ state.scrollLocked = true;
113
+ } else if (!shouldLock) unlockScroll(document, state);
114
+ if (modalIndex < 0) {
115
+ stopObserver(state);
116
+ return;
117
+ }
118
+ const protectedRoots = [];
119
+ for (const layer of state.layers.slice(modalIndex)) {
120
+ const element = layer.element.value;
121
+ if (element?.isConnected) protectedRoots.push(element);
122
+ for (const branch of layer.branches.value) if (branch.isConnected) protectedRoots.push(branch);
123
+ }
124
+ if (protectedRoots.length > 0) {
125
+ inertUnprotectedBranches(state, document.body, protectedRoots);
126
+ startObserver(document, state);
127
+ }
128
+ }
129
+ function removeLayer(layer, document, state) {
130
+ const index = state.layers.indexOf(layer);
131
+ if (index >= 0) state.layers.splice(index, 1);
132
+ syncLayerZIndices(state);
133
+ syncModalEffects(document, state);
134
+ }
135
+ function useOverlayLayer(options) {
136
+ const parent = inject(overlayLayerKey, null);
137
+ const active = computed(() => Boolean(toValue(options.active)));
138
+ const modal = computed(() => Boolean(toValue(options.modal ?? false)));
139
+ const preventScroll = computed(() => Boolean(toValue(options.preventScroll ?? true)));
140
+ const branches = shallowRef([]);
141
+ const focusBranches = shallowRef([]);
142
+ const branchSet = /* @__PURE__ */ new Set();
143
+ const focusBranchSet = /* @__PURE__ */ new Set();
144
+ const insideBranchSet = /* @__PURE__ */ new Set();
145
+ const zIndex = ref(options.baseZIndex ?? 100);
146
+ let registeredDocument = null;
147
+ let registeredElement = null;
148
+ let parentBranchCleanup;
149
+ function syncBranches() {
150
+ branches.value = [...branchSet];
151
+ focusBranches.value = [...focusBranchSet];
152
+ if (registeredDocument) syncModalEffects(registeredDocument, getState(registeredDocument));
153
+ }
154
+ function registerBranch(element, branchOptions = {}) {
155
+ branchSet.add(element);
156
+ if (branchOptions.focus !== false) focusBranchSet.add(element);
157
+ if (branchOptions.inside !== false) insideBranchSet.add(element);
158
+ const parentCleanup = parent?.registerBranch(element, branchOptions);
159
+ syncBranches();
160
+ return () => {
161
+ branchSet.delete(element);
162
+ focusBranchSet.delete(element);
163
+ insideBranchSet.delete(element);
164
+ parentCleanup?.();
165
+ syncBranches();
166
+ };
167
+ }
168
+ function replaceParentBranch(element) {
169
+ parentBranchCleanup?.();
170
+ parentBranchCleanup = element ? parent?.registerBranch(element) : void 0;
171
+ }
172
+ const context = {
173
+ id: Symbol("overlay-layer"),
174
+ element: options.element,
175
+ active,
176
+ modal,
177
+ modalEffects: options.modalEffects === true,
178
+ preventScroll,
179
+ branches,
180
+ focusBranches,
181
+ zIndex: readonly(zIndex),
182
+ isTopLayer() {
183
+ if (!registeredDocument) return false;
184
+ const layers = getState(registeredDocument).layers;
185
+ return layers[layers.length - 1] === context;
186
+ },
187
+ isInside(event, additional = []) {
188
+ return [
189
+ options.element.value,
190
+ ...insideBranchSet,
191
+ ...additional
192
+ ].some((element) => element != null && isEventWithinElement(event, element));
193
+ },
194
+ registerBranch
195
+ };
196
+ layerMetadata.set(context, {
197
+ baseZIndex: options.baseZIndex ?? 100,
198
+ parent,
199
+ setZIndex(value) {
200
+ zIndex.value = value;
201
+ }
202
+ });
203
+ function unregister() {
204
+ replaceParentBranch(null);
205
+ if (!registeredDocument) return;
206
+ const document = registeredDocument;
207
+ registeredDocument = null;
208
+ registeredElement = null;
209
+ removeLayer(context, document, getState(document));
210
+ }
211
+ function register(element) {
212
+ const document = element.ownerDocument;
213
+ if (registeredDocument === document) {
214
+ if (registeredElement !== element) {
215
+ replaceParentBranch(element);
216
+ registeredElement = element;
217
+ syncModalEffects(document, getState(document));
218
+ }
219
+ return;
220
+ }
221
+ unregister();
222
+ const state = getState(document);
223
+ const currentIndex = state.layers.indexOf(context);
224
+ if (currentIndex >= 0) state.layers.splice(currentIndex, 1);
225
+ const descendantIndex = state.layers.findIndex((layer) => isDescendantLayer(layer, context));
226
+ if (descendantIndex >= 0) state.layers.splice(descendantIndex, 0, context);
227
+ else state.layers.push(context);
228
+ registeredDocument = document;
229
+ registeredElement = element;
230
+ replaceParentBranch(element);
231
+ syncLayerZIndices(state);
232
+ syncModalEffects(document, state);
233
+ }
234
+ watch([active, options.element], ([isActive, element]) => {
235
+ if (isActive && element?.isConnected) register(element);
236
+ else unregister();
237
+ }, {
238
+ flush: "post",
239
+ immediate: true
240
+ });
241
+ watch([modal, preventScroll], () => {
242
+ if (registeredDocument) syncModalEffects(registeredDocument, getState(registeredDocument));
243
+ });
244
+ onBeforeUnmount(unregister);
245
+ provide(overlayLayerKey, context);
246
+ return context;
247
+ }
248
+ function useOverlayLayerBranch(element, options = {}) {
249
+ const layer = inject(overlayLayerKey, null);
250
+ let cleanup;
251
+ watch(element, (nextElement) => {
252
+ cleanup?.();
253
+ cleanup = nextElement ? layer?.registerBranch(nextElement, options) : void 0;
254
+ }, {
255
+ flush: "post",
256
+ immediate: true
257
+ });
258
+ onBeforeUnmount(() => cleanup?.());
259
+ return layer;
260
+ }
261
+ //#endregion
262
+ export { useOverlayLayerBranch as n, useOverlayLayer as t };
@@ -0,0 +1,40 @@
1
+ import { computed, inject, isRef, provide, toValue } from "vue";
2
+ //#region src/components/teleport-provider/useTeleportTarget.ts
3
+ var teleportTargetKey = Symbol("teleport-target");
4
+ function readTeleportTarget(target) {
5
+ return isRef(target) ? target.value : target;
6
+ }
7
+ function hasTarget(target) {
8
+ return target != null && target !== "";
9
+ }
10
+ function provideTeleportTarget(props, positioningKey) {
11
+ const parentContext = inject(teleportTargetKey, void 0);
12
+ const target = computed(() => {
13
+ const ownTarget = readTeleportTarget(props.teleportTo);
14
+ if (hasTarget(ownTarget)) return ownTarget;
15
+ return parentContext?.target.value ?? "body";
16
+ });
17
+ provide(teleportTargetKey, {
18
+ target,
19
+ positioningKey: computed(() => [
20
+ target.value,
21
+ toValue(positioningKey),
22
+ parentContext?.positioningKey.value
23
+ ])
24
+ });
25
+ return target;
26
+ }
27
+ function useTeleportTarget(target) {
28
+ const providedContext = inject(teleportTargetKey, void 0);
29
+ return computed(() => {
30
+ const ownTarget = readTeleportTarget(toValue(target));
31
+ if (hasTarget(ownTarget)) return ownTarget;
32
+ return providedContext?.target.value ?? "body";
33
+ });
34
+ }
35
+ function useTeleportPositioningKey() {
36
+ const providedContext = inject(teleportTargetKey, void 0);
37
+ return computed(() => providedContext?.positioningKey.value);
38
+ }
39
+ //#endregion
40
+ export { useTeleportPositioningKey as n, useTeleportTarget as r, provideTeleportTarget as t };
@@ -0,0 +1,148 @@
1
+ # Public floating API
2
+
3
+ `useFloatingPosition` provides Ropav's positioning behavior without rendering component DOM or
4
+ styles. It applies the same offset, flip, shift and collision defaults used by Ropav overlays.
5
+
6
+ ```vue
7
+ <template>
8
+ <button
9
+ ref="reference"
10
+ type="button"
11
+ aria-haspopup="dialog"
12
+ :aria-expanded="open"
13
+ @click="open = !open"
14
+ >
15
+ Toggle card
16
+ </button>
17
+
18
+ <Teleport :to="teleportTo" :disabled="!teleport">
19
+ <section v-if="open" ref="floating" :style="floatingStyle" :data-placement="actualPlacement">
20
+ Custom content
21
+ <span ref="arrow" :style="arrowStyle" aria-hidden="true" />
22
+ </section>
23
+ </Teleport>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { ref } from 'vue';
28
+ import { useFloatingPosition } from 'ropav/floating';
29
+ import { useTeleportTarget } from 'ropav/teleport-provider';
30
+
31
+ const reference = ref<HTMLElement | null>(null);
32
+ const floating = ref<HTMLElement | null>(null);
33
+ const arrow = ref<HTMLElement | null>(null);
34
+ const open = ref(false);
35
+ const teleport = ref(true);
36
+ const teleportTo = useTeleportTarget();
37
+
38
+ const { actualPlacement, arrowStyle, floatingStyle } = useFloatingPosition({
39
+ reference,
40
+ floating,
41
+ arrow,
42
+ open,
43
+ placement: 'bottom-start',
44
+ offset: 8,
45
+ restartKey: () => [teleport.value, teleportTo.value],
46
+ });
47
+ </script>
48
+ ```
49
+
50
+ The composable accepts plain values, refs, computed refs or getters for reactive options.
51
+
52
+ | Option | Default | Description |
53
+ | ------------------ | ---------- | -------------------------------------------------------------- |
54
+ | `reference` | required | Element or virtual element used as the anchor. |
55
+ | `floating` | required | Floating HTML element. |
56
+ | `arrow` | — | Optional arrow HTML element. |
57
+ | `open` | `true` | Suspends positioning and auto-updates when false. |
58
+ | `placement` | `bottom` | Preferred side and optional alignment. |
59
+ | `strategy` | `absolute` | CSS positioning strategy: `absolute` or `fixed`. |
60
+ | `offset` | `8` | Main/cross-axis distance from the reference. |
61
+ | `flip` | `true` | Tries the opposite side when space is insufficient. |
62
+ | `shift` | `true` | Keeps the floating element inside the collision boundary. |
63
+ | `collisionPadding` | `8` | Padding between the floating element and viewport boundary. |
64
+ | `restartKey` | — | Rebinds auto-update observers when its reactive value changes. |
65
+
66
+ The return value contains readonly `actualPlacement`, `floatingStyle`, `arrowStyle` and
67
+ `isPositioned` refs, plus an async `update()` method for content-driven layout changes.
68
+
69
+ `useTeleportTarget()` resolves the nearest `TeleportProvider` target and falls back to `body`. Pass
70
+ a target value, ref or getter to override the provider for one floating element. Include the
71
+ resolved target and the Teleport enabled state in `restartKey` whenever either can change while the
72
+ floating element is open.
73
+
74
+ Positioning does not add interaction or accessibility behavior. Custom overlays remain responsible
75
+ for keyboard handling, focus management, roles, labels, outside interaction and dismissal.
76
+
77
+ ## Hover disclosure interactions
78
+
79
+ `useHoverDisclosure` manages hover and focus state without rendering DOM or positioning content. It
80
+ coordinates the trigger and floating content, so a close delay started when the pointer leaves the
81
+ trigger is cancelled when the pointer enters the content.
82
+
83
+ ```vue
84
+ <template>
85
+ <a ref="reference" href="/people/ada" v-bind="triggerProps">Ada Lovelace</a>
86
+
87
+ <Teleport to="body">
88
+ <section
89
+ v-if="isOpen"
90
+ ref="floating"
91
+ v-bind="contentProps"
92
+ :style="floatingStyle"
93
+ :data-placement="actualPlacement"
94
+ >
95
+ Mathematician and writer
96
+ </section>
97
+ </Teleport>
98
+ </template>
99
+
100
+ <script setup lang="ts">
101
+ import { ref } from 'vue';
102
+ import { useFloatingPosition, useHoverDisclosure } from 'ropav/floating';
103
+
104
+ const reference = ref<HTMLElement | null>(null);
105
+ const floating = ref<HTMLElement | null>(null);
106
+
107
+ const { isOpen, triggerProps, contentProps } = useHoverDisclosure({
108
+ openDelay: 600,
109
+ closeDelay: 150,
110
+ });
111
+
112
+ const { actualPlacement, floatingStyle } = useFloatingPosition({
113
+ reference,
114
+ floating,
115
+ open: isOpen,
116
+ placement: 'bottom-start',
117
+ });
118
+ </script>
119
+ ```
120
+
121
+ Focus opens immediately by default. Hover uses `openDelay`; leaving the combined trigger/content
122
+ area uses `closeDelay`. Escape dismisses an open disclosure even when keyboard focus is elsewhere.
123
+ The return value also contains `state`, `isDisabled`, and immediate `open()`, `close()` and
124
+ `toggle()` controls.
125
+
126
+ | Option | Default | Description |
127
+ | ------------------- | ------- | --------------------------------------------------------------------------- |
128
+ | `open` | — | Controlled open state. Omit it for internal state. |
129
+ | `defaultOpen` | `false` | Initial internal state. |
130
+ | `openDelay` | `0` | Delay in milliseconds before pointer hover opens the disclosure. |
131
+ | `closeDelay` | `0` | Delay before closing after pointer and focus leave trigger and content. |
132
+ | `disabled` | `false` | Prevents opening and closes pending/open internal state. |
133
+ | `openOnFocus` | `true` | Opens immediately when focus enters the trigger. |
134
+ | `closeOnEscape` | `true` | Allows Escape to dismiss the disclosure. |
135
+ | `touchBehavior` | `none` | `toggle` opts into tap-to-toggle and prevents the activating click default. |
136
+ | `interactionTarget` | — | External element, selector or virtual reference that owns trigger events. |
137
+ | `contentTarget` | — | External element or selector that owns content events. |
138
+ | `onOpenChange` | — | Receives the requested state and its interaction reason. |
139
+
140
+ When `interactionTarget` or `contentTarget` is supplied, the composable attaches the corresponding
141
+ listeners directly; do not also bind the matching props to that same element. An element reference
142
+ is used directly. A virtual reference uses its `contextElement` for events. A virtual reference
143
+ without `contextElement` cannot receive pointer or focus events, so control it with `open` or the
144
+ imperative methods instead.
145
+
146
+ The composable only owns disclosure interaction. Consumers remain responsible for content roles,
147
+ labels and deciding whether the revealed information is appropriate for hover/focus. Interactive
148
+ dialogs and focus-trapped content should use `Popover` or `Dialog` instead.