ropav 0.1.7 → 0.1.8

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 (153) hide show
  1. package/README.md +1 -1
  2. package/dist/ancestry.js +136 -0
  3. package/dist/calendar.css +173 -0
  4. package/dist/calendar.js +714 -0
  5. package/dist/calendar2.js +37 -0
  6. package/dist/chevron-left.js +12 -0
  7. package/dist/color-picker.js +38 -88
  8. package/dist/combobox.css +251 -0
  9. package/dist/combobox.js +410 -0
  10. package/dist/components/calendar/calendar.d.ts +30 -0
  11. package/dist/components/calendar/calendarBehavior.d.ts +49 -0
  12. package/dist/components/calendar/index.d.ts +3 -0
  13. package/dist/components/calendar/index.js +3 -0
  14. package/dist/components/calendar/types.d.ts +53 -0
  15. package/dist/components/calendar/useCalendar.d.ts +24 -0
  16. package/dist/components/color-picker/useColorPickerDrag.d.ts +1 -1
  17. package/dist/components/color-picker/useColorPickerSaturation.d.ts +1 -1
  18. package/dist/components/color-picker/useColorPickerSlider.d.ts +1 -1
  19. package/dist/components/combobox/combobox.d.ts +29 -0
  20. package/dist/components/combobox/comboboxModel.d.ts +4 -0
  21. package/dist/components/combobox/index.d.ts +3 -0
  22. package/dist/components/combobox/index.js +2 -0
  23. package/dist/components/combobox/types.d.ts +43 -0
  24. package/dist/components/combobox/useCombobox.d.ts +45 -0
  25. package/dist/components/date-picker/date-picker.d.ts +33 -0
  26. package/dist/components/date-picker/datePickerModel.d.ts +10 -0
  27. package/dist/components/date-picker/index.d.ts +4 -0
  28. package/dist/components/date-picker/index.js +2 -0
  29. package/dist/components/date-picker/types.d.ts +57 -0
  30. package/dist/components/date-picker/useDatePicker.d.ts +29 -0
  31. package/dist/components/date-picker/useDatePickerValueState.d.ts +21 -0
  32. package/dist/components/dropdown-menu/dropdown-menu-content.d.ts +2 -2
  33. package/dist/components/dropdown-menu/dropdown-menu-sub-content.d.ts +2 -2
  34. package/dist/components/dropdown-menu/dropdown-menu.d.ts +2 -2
  35. package/dist/components/dropdown-menu/dropdownMenuContext.d.ts +7 -18
  36. package/dist/components/dropdown-menu/dropdownMenuInteraction.d.ts +3 -3
  37. package/dist/components/dropdown-menu/dropdownMenuInteractionTypes.d.ts +58 -29
  38. package/dist/components/dropdown-menu/useDropdownMenuDataController.d.ts +4 -3
  39. package/dist/components/dropdown-menu/useDropdownMenuDataRegistration.d.ts +6 -4
  40. package/dist/components/dropdown-menu/useDropdownMenuPresentation.d.ts +3 -4
  41. package/dist/components/dropdown-menu/useDropdownMenuTargetBindings.d.ts +5 -5
  42. package/dist/components/dropzone/dropzone.d.ts +31 -0
  43. package/dist/components/dropzone/dropzoneModel.d.ts +16 -0
  44. package/dist/components/dropzone/index.d.ts +3 -0
  45. package/dist/components/dropzone/index.js +2 -0
  46. package/dist/components/dropzone/types.d.ts +56 -0
  47. package/dist/components/dropzone/useDropzone.d.ts +25 -0
  48. package/dist/components/file-input/file-input.d.ts +29 -0
  49. package/dist/components/file-input/index.d.ts +3 -0
  50. package/dist/components/file-input/index.js +2 -0
  51. package/dist/components/file-input/types.d.ts +37 -0
  52. package/dist/components/file-input/useFileInput.d.ts +15 -0
  53. package/dist/components/floating/index.js +1 -1
  54. package/dist/components/floating/useFloatingPosition.d.ts +1 -13
  55. package/dist/components/floating/useFloatingTargetLifecycle.d.ts +32 -0
  56. package/dist/components/floating/useHoverDisclosure.d.ts +10 -0
  57. package/dist/components/hover-card/hover-card.d.ts +25 -0
  58. package/dist/components/hover-card/index.d.ts +3 -0
  59. package/dist/components/hover-card/index.js +2 -0
  60. package/dist/components/hover-card/types.d.ts +45 -0
  61. package/dist/components/hover-card/useHoverCard.d.ts +22 -0
  62. package/dist/components/hover-card/useHoverCardDisclosure.d.ts +19 -0
  63. package/dist/components/multi-select/index.d.ts +3 -0
  64. package/dist/components/multi-select/index.js +2 -0
  65. package/dist/components/multi-select/multi-select.d.ts +30 -0
  66. package/dist/components/multi-select/multiSelectModel.d.ts +3 -0
  67. package/dist/components/multi-select/types.d.ts +49 -0
  68. package/dist/components/multi-select/useMultiSelect.d.ts +46 -0
  69. package/dist/components/number-input/useNumberInput.d.ts +1 -3
  70. package/dist/components/popover/usePopoverBindings.d.ts +3 -6
  71. package/dist/components/scroll-area/useScrollArea.d.ts +4 -4
  72. package/dist/components/scroll-area/useScrollAreaAttributes.d.ts +3 -3
  73. package/dist/components/scroll-area/useScrollAreaPointer.d.ts +1 -1
  74. package/dist/components/segmented-control/index.d.ts +3 -0
  75. package/dist/components/segmented-control/index.js +2 -0
  76. package/dist/components/segmented-control/segmented-control.d.ts +26 -0
  77. package/dist/components/segmented-control/types.d.ts +47 -0
  78. package/dist/components/segmented-control/useSegmentedControl.d.ts +15 -0
  79. package/dist/components/select/useSelect.d.ts +31 -19
  80. package/dist/components/slider/useRangeSlider.d.ts +1 -1
  81. package/dist/components/slider/useRangeSliderPointer.d.ts +1 -1
  82. package/dist/components/tags-input/index.d.ts +3 -0
  83. package/dist/components/tags-input/index.js +2 -0
  84. package/dist/components/tags-input/tags-input.d.ts +27 -0
  85. package/dist/components/tags-input/tagsInputModel.d.ts +12 -0
  86. package/dist/components/tags-input/types.d.ts +37 -0
  87. package/dist/components/tags-input/useTagsInput.d.ts +23 -0
  88. package/dist/components/tooltip/useTooltipTargetBindings.d.ts +12 -0
  89. package/dist/date-picker.css +49 -0
  90. package/dist/date-picker.js +809 -0
  91. package/dist/dialog.js +9 -20
  92. package/dist/direction.js +6 -0
  93. package/dist/dropdown-menu.css +21 -3
  94. package/dist/dropdown-menu.js +341 -261
  95. package/dist/dropzone.css +135 -0
  96. package/dist/dropzone.js +431 -0
  97. package/dist/file-input.css +135 -0
  98. package/dist/file-input.js +198 -0
  99. package/dist/hover-card.css +80 -0
  100. package/dist/hover-card.js +402 -0
  101. package/dist/index.d.ts +9 -0
  102. package/dist/index.js +14 -3
  103. package/dist/internal/composables/useOverlayLayer.d.ts +12 -0
  104. package/dist/modal.js +1 -1
  105. package/dist/multi-select.css +316 -0
  106. package/dist/multi-select.js +481 -0
  107. package/dist/nativeChoice.js +169 -0
  108. package/dist/number-input.css +18 -18
  109. package/dist/number-input.js +36 -38
  110. package/dist/pagination.js +1 -10
  111. package/dist/pointerSession.js +130 -0
  112. package/dist/popover.css +21 -3
  113. package/dist/popover.js +37 -62
  114. package/dist/scroll-area.js +52 -62
  115. package/dist/segmented-control.css +176 -0
  116. package/dist/segmented-control.js +382 -0
  117. package/dist/select.css +50 -48
  118. package/dist/select.js +121 -271
  119. package/dist/slider.js +70 -129
  120. package/dist/tags-input.css +197 -0
  121. package/dist/tags-input.js +380 -0
  122. package/dist/tooltip.js +35 -30
  123. package/dist/useEditableOptionList.js +216 -0
  124. package/dist/useFlatOptionCollection.js +134 -0
  125. package/dist/useFloatingPosition.js +4 -160
  126. package/dist/useFloatingTargetLifecycle.js +127 -0
  127. package/dist/useFormControl.js +1 -0
  128. package/dist/{floating.js → useHoverDisclosure.js} +338 -421
  129. package/dist/useNativeChoiceTransaction.js +46 -0
  130. package/dist/useNativeFileSelection.js +86 -0
  131. package/dist/useOverlayZIndex.js +246 -15
  132. package/dist/utils/date.d.ts +13 -0
  133. package/dist/utils/dateAvailability.d.ts +7 -0
  134. package/dist/utils/dom/ancestry.d.ts +1 -0
  135. package/dist/utils/dom/direction.d.ts +2 -0
  136. package/dist/utils/dom/files.d.ts +3 -0
  137. package/dist/utils/dom/nativeChoice.d.ts +17 -0
  138. package/dist/utils/dom/pointerSession.d.ts +20 -0
  139. package/dist/utils/dom/scroll.d.ts +2 -1
  140. package/dist/utils/optionFilter.d.ts +5 -0
  141. package/docs/public-floating-api.md +7 -4
  142. package/docs/public-styles-api.md +25 -12
  143. package/package.json +39 -3
  144. package/src/styles/_mixins.scss +26 -0
  145. package/src/styles/styles-manifest.json +1 -2
  146. package/dist/components/floating/hoverDisclosureInteractionModel.d.ts +0 -42
  147. package/dist/components/floating/useHoverDisclosureInteractions.d.ts +0 -32
  148. package/dist/components/floating/useHoverDisclosureOpenState.d.ts +0 -25
  149. package/dist/components/floating/useHoverDisclosureTargetBinding.d.ts +0 -27
  150. package/dist/components/select/useSelectNativeControl.d.ts +0 -9
  151. package/dist/components/select/useSelectNativeValue.d.ts +0 -9
  152. package/dist/pointer.js +0 -9
  153. package/dist/utils/dom/pointer.d.ts +0 -2
@@ -0,0 +1,46 @@
1
+ import { t as useControllableValue } from "./useControllableValue.js";
2
+ import { i as useFormControl } from "./useFormControl.js";
3
+ import { nextTick, watchEffect } from "vue";
4
+ //#region src/internal/composables/useNativeChoiceTransaction.ts
5
+ function useNativeChoiceTransaction(options) {
6
+ const controllable = useControllableValue(options.value);
7
+ function syncNativeValue(value) {
8
+ options.adapter.syncValue(value, controllable.initialValue);
9
+ }
10
+ function restoreControlledValue() {
11
+ if (!controllable.isControlled.value) return;
12
+ queueMicrotask(() => syncNativeValue(controllable.value.value));
13
+ }
14
+ function requestValueUpdate(value) {
15
+ options.adapter.commitValue(value, controllable.initialValue, () => controllable.setValue(value));
16
+ restoreControlledValue();
17
+ }
18
+ useFormControl({
19
+ elements: options.adapter.controls,
20
+ isControlled: () => controllable.isControlled.value,
21
+ validationMessage: options.adapter.validationMessage,
22
+ readResetValue(controls) {
23
+ controllable.resetValue(options.adapter.readResetValue(controls, controllable.initialValue));
24
+ syncNativeValue(controllable.value.value);
25
+ options.onFormReset?.();
26
+ },
27
+ syncControlledValue() {
28
+ syncNativeValue(controllable.value.value);
29
+ options.onFormReset?.();
30
+ }
31
+ });
32
+ watchEffect(() => {
33
+ const currentValue = controllable.value.value;
34
+ const reconciledValue = options.adapter.reconcileValue?.(currentValue, controllable.initialValue, controllable.isControlled.value) ?? currentValue;
35
+ if (!controllable.isControlled.value && !Object.is(reconciledValue, currentValue)) controllable.resetValue(reconciledValue);
36
+ syncNativeValue(controllable.value.value);
37
+ nextTick(() => syncNativeValue(controllable.value.value));
38
+ }, { flush: "post" });
39
+ return {
40
+ isControlled: controllable.isControlled,
41
+ requestValueUpdate,
42
+ value: controllable.value
43
+ };
44
+ }
45
+ //#endregion
46
+ export { useNativeChoiceTransaction as t };
@@ -0,0 +1,86 @@
1
+ import { t as useControllableValue } from "./useControllableValue.js";
2
+ import { i as useFormControl } from "./useFormControl.js";
3
+ import { computed, nextTick, ref, watchEffect } from "vue";
4
+ //#region src/utils/dom/files.ts
5
+ function normalizeSelectedFiles(files, multiple) {
6
+ const selectedFiles = Array.from(files);
7
+ return multiple ? selectedFiles : selectedFiles.slice(0, 1);
8
+ }
9
+ function haveSameFiles(fileList, files) {
10
+ if (!fileList || fileList.length !== files.length) return false;
11
+ return files.every((file, index) => fileList.item(index) === file);
12
+ }
13
+ function replaceInputFiles(input, files) {
14
+ if (haveSameFiles(input.files, files)) return true;
15
+ if (files.length === 0) {
16
+ input.value = "";
17
+ return true;
18
+ }
19
+ const DataTransferConstructor = input.ownerDocument.defaultView?.DataTransfer;
20
+ if (!DataTransferConstructor) return false;
21
+ const transfer = new DataTransferConstructor();
22
+ for (const file of files) transfer.items.add(file);
23
+ try {
24
+ input.files = transfer.files;
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ //#endregion
31
+ //#region src/internal/composables/useNativeFileSelection.ts
32
+ function useNativeFileSelection(options) {
33
+ const inputRef = ref(null);
34
+ const controllable = useControllableValue({
35
+ modelValue: options.modelValue,
36
+ defaultValue: () => [],
37
+ onChange: options.onChange
38
+ });
39
+ const files = computed(() => normalizeSelectedFiles(controllable.value.value, options.multiple()));
40
+ function syncNativeFiles(nextFiles = files.value) {
41
+ const input = inputRef.value;
42
+ if (input) replaceInputFiles(input, nextFiles);
43
+ }
44
+ function settleSelection(outcome) {
45
+ if (outcome.status === "accepted") {
46
+ const nextFiles = normalizeSelectedFiles(outcome.files, options.multiple());
47
+ syncNativeFiles(nextFiles);
48
+ controllable.setValue(nextFiles);
49
+ } else syncNativeFiles();
50
+ nextTick(() => syncNativeFiles());
51
+ }
52
+ function clear() {
53
+ settleSelection({
54
+ status: "accepted",
55
+ files: []
56
+ });
57
+ }
58
+ function focus(focusOptions) {
59
+ inputRef.value?.focus(focusOptions);
60
+ }
61
+ function open() {
62
+ if (options.disabled()) return;
63
+ inputRef.value?.click();
64
+ }
65
+ watchEffect(() => syncNativeFiles(files.value), { flush: "post" });
66
+ useFormControl({
67
+ elements: () => [inputRef.value],
68
+ isControlled: () => controllable.isControlled.value,
69
+ validationMessage: options.validationMessage,
70
+ readResetValue() {
71
+ controllable.resetValue([]);
72
+ settleSelection({ status: "rejected" });
73
+ },
74
+ syncControlledValue: () => settleSelection({ status: "rejected" })
75
+ });
76
+ return {
77
+ inputRef,
78
+ files,
79
+ settleSelection,
80
+ clear,
81
+ focus,
82
+ open
83
+ };
84
+ }
85
+ //#endregion
86
+ export { useNativeFileSelection as t };
@@ -1,13 +1,40 @@
1
1
  import { n as isEventWithinElement } from "./events.js";
2
+ import { n as observeComposedAncestry } from "./ancestry.js";
2
3
  import { computed, inject, onBeforeUnmount, provide, readonly, ref, shallowRef, toValue, watch } from "vue";
3
4
  //#region src/internal/composables/useOverlayLayer.ts
4
5
  var overlayLayerKey = Symbol("overlay-layer");
5
6
  var documentStates = /* @__PURE__ */ new WeakMap();
7
+ var activeInteractionLayers = [];
8
+ var interactionListenerDefinitions = {
9
+ escapeKeyDown: {
10
+ capture: false,
11
+ eventName: "keydown",
12
+ outside: false,
13
+ matches: (event) => event.key === "Escape"
14
+ },
15
+ pointerDownOutside: {
16
+ capture: true,
17
+ eventName: "pointerdown",
18
+ outside: true
19
+ },
20
+ focusOutside: {
21
+ capture: true,
22
+ eventName: "focusin",
23
+ outside: true
24
+ },
25
+ clickOutside: {
26
+ capture: true,
27
+ eventName: "click",
28
+ outside: true
29
+ }
30
+ };
6
31
  var layerMetadata = /* @__PURE__ */ new WeakMap();
7
32
  function createState() {
8
33
  return {
9
34
  layers: [],
35
+ interactionLayers: [],
10
36
  inertSnapshots: /* @__PURE__ */ new Map(),
37
+ interactionListeners: {},
11
38
  originalBodyOverflow: "",
12
39
  scrollLocked: false,
13
40
  observer: null,
@@ -29,6 +56,24 @@ function isDescendantLayer(layer, ancestor) {
29
56
  }
30
57
  return false;
31
58
  }
59
+ function insertLayer(layers, layer) {
60
+ const currentIndex = layers.indexOf(layer);
61
+ if (currentIndex >= 0) layers.splice(currentIndex, 1);
62
+ const descendantIndex = layers.findIndex((candidate) => isDescendantLayer(candidate, layer));
63
+ if (descendantIndex >= 0) layers.splice(descendantIndex, 0, layer);
64
+ else layers.push(layer);
65
+ }
66
+ function insertPhysicalLayer(layers, layer) {
67
+ removeLayerFromStack(layers, layer);
68
+ const layerIndex = activeInteractionLayers.indexOf(layer);
69
+ const nextIndex = layers.findIndex((candidate) => activeInteractionLayers.indexOf(candidate) > layerIndex);
70
+ if (nextIndex >= 0) layers.splice(nextIndex, 0, layer);
71
+ else layers.push(layer);
72
+ }
73
+ function removeLayerFromStack(layers, layer) {
74
+ const index = layers.indexOf(layer);
75
+ if (index >= 0) layers.splice(index, 1);
76
+ }
32
77
  function syncLayerZIndices(state) {
33
78
  let highestZIndex = Number.NEGATIVE_INFINITY;
34
79
  for (const layer of state.layers) {
@@ -39,6 +84,65 @@ function syncLayerZIndices(state) {
39
84
  highestZIndex = zIndex;
40
85
  }
41
86
  }
87
+ function syncDocumentInteractionLayers(document) {
88
+ const state = getState(document);
89
+ state.interactionLayers = activeInteractionLayers.filter((layer) => layerMetadata.get(layer)?.interactionDocuments.has(document));
90
+ syncInteractionListeners(document, state);
91
+ }
92
+ function reconcileInteractionDocuments(layer) {
93
+ const affectedDocuments = /* @__PURE__ */ new Set();
94
+ const layers = activeInteractionLayers.filter((candidate) => candidate === layer || isDescendantLayer(candidate, layer));
95
+ if (!layers.includes(layer)) layers.unshift(layer);
96
+ for (const candidate of layers) {
97
+ const metadata = layerMetadata.get(candidate);
98
+ if (!metadata) continue;
99
+ for (const document of metadata.interactionDocuments) affectedDocuments.add(document);
100
+ const nextDocuments = metadata.registered ? new Set(metadata.ownInteractionDocuments) : /* @__PURE__ */ new Set();
101
+ const parentDocuments = metadata.parent ? layerMetadata.get(metadata.parent)?.interactionDocuments : void 0;
102
+ if (metadata.registered && parentDocuments) for (const document of parentDocuments) nextDocuments.add(document);
103
+ metadata.interactionDocuments = nextDocuments;
104
+ for (const document of nextDocuments) affectedDocuments.add(document);
105
+ }
106
+ for (const document of affectedDocuments) syncDocumentInteractionLayers(document);
107
+ }
108
+ function hasInteractionHandler(state, name) {
109
+ return state.interactionLayers.some((layer) => [...layerMetadata.get(layer)?.interactions ?? []].some((interaction) => typeof interaction[name] === "function"));
110
+ }
111
+ function routeLayerInteraction(state, name, event) {
112
+ const layer = state.interactionLayers[state.interactionLayers.length - 1];
113
+ if (!layer) return;
114
+ const definition = interactionListenerDefinitions[name];
115
+ if (definition.matches && !definition.matches(event)) return;
116
+ const interactions = [...layerMetadata.get(layer)?.interactions ?? []];
117
+ for (const interaction of interactions) {
118
+ const handler = interaction[name];
119
+ if (!handler) continue;
120
+ const additionalInside = interaction.inside ? toValue(interaction.inside) : [];
121
+ if (definition.outside && layer.isInside(event, additionalInside)) continue;
122
+ handler(event);
123
+ }
124
+ }
125
+ function syncInteractionListeners(document, state) {
126
+ for (const name of Object.keys(interactionListenerDefinitions)) {
127
+ const existing = state.interactionListeners[name];
128
+ if (!hasInteractionHandler(state, name)) {
129
+ if (existing) {
130
+ document.removeEventListener(existing.eventName, existing.listener, existing.capture);
131
+ delete state.interactionListeners[name];
132
+ }
133
+ continue;
134
+ }
135
+ if (existing) continue;
136
+ const definition = interactionListenerDefinitions[name];
137
+ const listener = (event) => routeLayerInteraction(state, name, event);
138
+ document.addEventListener(definition.eventName, listener, definition.capture);
139
+ state.interactionListeners[name] = {
140
+ capture: definition.capture,
141
+ eventName: definition.eventName,
142
+ listener
143
+ };
144
+ }
145
+ }
42
146
  function restoreInertBackground(state) {
43
147
  for (const [element, snapshot] of state.inertSnapshots) {
44
148
  element.inert = snapshot.inert;
@@ -123,11 +227,41 @@ function syncModalEffects(document, state) {
123
227
  }
124
228
  }
125
229
  function removeLayer(layer, document, state) {
126
- const index = state.layers.indexOf(layer);
127
- if (index >= 0) state.layers.splice(index, 1);
230
+ removeLayerFromStack(state.layers, layer);
128
231
  syncLayerZIndices(state);
129
232
  syncModalEffects(document, state);
130
233
  }
234
+ function createOverlayLayerAncestryObserver(options) {
235
+ let cleanups = [];
236
+ let disposed = false;
237
+ function stop() {
238
+ for (const cleanup of cleanups) cleanup();
239
+ cleanups = [];
240
+ }
241
+ function reset() {
242
+ stop();
243
+ if (disposed || !options.active.value) return;
244
+ const content = options.element.value;
245
+ if (content) cleanups.push(observeComposedAncestry(() => [content], options.onContentChange, { deferWhileDisconnected: true }));
246
+ const auxiliaryElements = new Set(options.branches);
247
+ for (const interaction of options.interactions) {
248
+ if (!interaction.inside) continue;
249
+ for (const element of toValue(interaction.inside)) if (element) auxiliaryElements.add(element);
250
+ }
251
+ if (content) auxiliaryElements.delete(content);
252
+ for (const element of auxiliaryElements) cleanups.push(observeComposedAncestry(() => [element], options.onAuxiliaryChange, {
253
+ deferWhileDisconnected: true,
254
+ notifyOnDisconnect: true
255
+ }));
256
+ }
257
+ return {
258
+ reset,
259
+ dispose() {
260
+ disposed = true;
261
+ stop();
262
+ }
263
+ };
264
+ }
131
265
  function useOverlayLayer(options) {
132
266
  const parent = inject(overlayLayerKey, null);
133
267
  const active = computed(() => Boolean(toValue(options.active)));
@@ -138,14 +272,26 @@ function useOverlayLayer(options) {
138
272
  const branchSet = /* @__PURE__ */ new Set();
139
273
  const focusBranchSet = /* @__PURE__ */ new Set();
140
274
  const insideBranchSet = /* @__PURE__ */ new Set();
275
+ const interactions = /* @__PURE__ */ new Set();
276
+ const interactionSetRevision = ref(0);
141
277
  const baseZIndex = computed(() => toValue(options.baseZIndex ?? 100));
142
278
  const zIndex = ref(baseZIndex.value);
143
279
  let registeredDocument = null;
144
280
  let registeredElement = null;
145
281
  let parentBranchCleanup;
282
+ const ancestryObserver = createOverlayLayerAncestryObserver({
283
+ active,
284
+ element: options.element,
285
+ branches: branchSet,
286
+ interactions,
287
+ onContentChange: syncObservedAncestry,
288
+ onAuxiliaryChange: syncObservedAuxiliaryAncestry
289
+ });
146
290
  function syncBranches() {
147
291
  branches.value = [...branchSet];
148
292
  focusBranches.value = [...focusBranchSet];
293
+ syncOwnInteractionDocuments();
294
+ ancestryObserver.reset();
149
295
  if (registeredDocument) syncModalEffects(registeredDocument, getState(registeredDocument));
150
296
  }
151
297
  function registerBranch(element, branchOptions = {}) {
@@ -166,6 +312,36 @@ function useOverlayLayer(options) {
166
312
  parentBranchCleanup?.();
167
313
  parentBranchCleanup = element ? parent?.registerBranch(element) : void 0;
168
314
  }
315
+ function connectInteraction(interaction) {
316
+ interactions.add(interaction);
317
+ interactionSetRevision.value += 1;
318
+ let connected = true;
319
+ return Object.assign(() => {
320
+ if (!connected) return;
321
+ connected = false;
322
+ interactions.delete(interaction);
323
+ interactionSetRevision.value += 1;
324
+ }, { refresh() {
325
+ if (!connected) return;
326
+ syncOwnInteractionDocuments();
327
+ ancestryObserver.reset();
328
+ } });
329
+ }
330
+ function readOwnInteractionDocuments() {
331
+ const documents = /* @__PURE__ */ new Set();
332
+ if (registeredElement) documents.add(registeredElement.ownerDocument);
333
+ for (const branch of branchSet) if (branch.isConnected) documents.add(branch.ownerDocument);
334
+ for (const interaction of interactions) if (interaction.inside) {
335
+ for (const element of toValue(interaction.inside)) if (element?.isConnected) documents.add(element.ownerDocument);
336
+ }
337
+ return [...documents];
338
+ }
339
+ function syncOwnInteractionDocuments(documents = readOwnInteractionDocuments()) {
340
+ const metadata = layerMetadata.get(context);
341
+ if (!metadata) return;
342
+ metadata.ownInteractionDocuments = new Set(documents);
343
+ reconcileInteractionDocuments(context);
344
+ }
169
345
  const context = {
170
346
  id: Symbol("overlay-layer"),
171
347
  element: options.element,
@@ -188,49 +364,100 @@ function useOverlayLayer(options) {
188
364
  ...additional
189
365
  ].some((element) => element != null && isEventWithinElement(event, element));
190
366
  },
191
- registerBranch
367
+ registerBranch,
368
+ connectInteraction
192
369
  };
193
370
  layerMetadata.set(context, {
194
371
  baseZIndex,
372
+ interactions,
373
+ interactionDocuments: /* @__PURE__ */ new Set(),
374
+ ownInteractionDocuments: /* @__PURE__ */ new Set(),
195
375
  parent,
376
+ registered: false,
196
377
  setZIndex(value) {
197
378
  zIndex.value = value;
198
379
  }
199
380
  });
381
+ watch(() => {
382
+ interactionSetRevision.value;
383
+ return readOwnInteractionDocuments();
384
+ }, (documents) => {
385
+ syncOwnInteractionDocuments(documents);
386
+ ancestryObserver.reset();
387
+ }, {
388
+ flush: "sync",
389
+ immediate: true
390
+ });
200
391
  function unregister() {
201
- replaceParentBranch(null);
202
392
  if (!registeredDocument) return;
203
393
  const document = registeredDocument;
204
394
  registeredDocument = null;
205
395
  registeredElement = null;
396
+ const metadata = layerMetadata.get(context);
397
+ if (metadata) metadata.registered = false;
398
+ removeLayerFromStack(activeInteractionLayers, context);
399
+ syncOwnInteractionDocuments();
400
+ replaceParentBranch(null);
206
401
  removeLayer(context, document, getState(document));
207
402
  }
403
+ function moveRegistration(element) {
404
+ const previousDocument = registeredDocument;
405
+ if (!previousDocument) return;
406
+ registeredDocument = element.ownerDocument;
407
+ registeredElement = element;
408
+ removeLayer(context, previousDocument, getState(previousDocument));
409
+ const state = getState(registeredDocument);
410
+ insertPhysicalLayer(state.layers, context);
411
+ syncOwnInteractionDocuments();
412
+ replaceParentBranch(element);
413
+ syncLayerZIndices(state);
414
+ syncModalEffects(registeredDocument, state);
415
+ }
208
416
  function register(element) {
209
417
  const document = element.ownerDocument;
210
418
  if (registeredDocument === document) {
211
419
  if (registeredElement !== element) {
212
- replaceParentBranch(element);
213
420
  registeredElement = element;
421
+ syncOwnInteractionDocuments();
422
+ replaceParentBranch(element);
214
423
  syncModalEffects(document, getState(document));
215
424
  }
216
425
  return;
217
426
  }
218
- unregister();
427
+ if (registeredDocument) {
428
+ moveRegistration(element);
429
+ return;
430
+ }
219
431
  const state = getState(document);
220
- const currentIndex = state.layers.indexOf(context);
221
- if (currentIndex >= 0) state.layers.splice(currentIndex, 1);
222
- const descendantIndex = state.layers.findIndex((layer) => isDescendantLayer(layer, context));
223
- if (descendantIndex >= 0) state.layers.splice(descendantIndex, 0, context);
224
- else state.layers.push(context);
225
432
  registeredDocument = document;
226
433
  registeredElement = element;
434
+ const metadata = layerMetadata.get(context);
435
+ if (metadata) metadata.registered = true;
436
+ insertLayer(activeInteractionLayers, context);
437
+ insertPhysicalLayer(state.layers, context);
438
+ syncOwnInteractionDocuments();
227
439
  replaceParentBranch(element);
228
440
  syncLayerZIndices(state);
229
441
  syncModalEffects(document, state);
230
442
  }
231
- watch([active, options.element], ([isActive, element]) => {
232
- if (isActive && element?.isConnected) register(element);
233
- else unregister();
443
+ function syncRegistration() {
444
+ const element = options.element.value;
445
+ if (active.value && element?.isConnected) {
446
+ register(element);
447
+ syncOwnInteractionDocuments();
448
+ } else unregister();
449
+ }
450
+ function syncObservedAncestry() {
451
+ syncRegistration();
452
+ if (registeredDocument) syncModalEffects(registeredDocument, getState(registeredDocument));
453
+ }
454
+ function syncObservedAuxiliaryAncestry() {
455
+ syncOwnInteractionDocuments();
456
+ if (registeredDocument) syncModalEffects(registeredDocument, getState(registeredDocument));
457
+ }
458
+ watch([active, options.element], () => {
459
+ syncRegistration();
460
+ ancestryObserver.reset();
234
461
  }, {
235
462
  flush: "post",
236
463
  immediate: true
@@ -242,7 +469,11 @@ function useOverlayLayer(options) {
242
469
  if (registeredDocument) syncLayerZIndices(getState(registeredDocument));
243
470
  else zIndex.value = value;
244
471
  });
245
- onBeforeUnmount(unregister);
472
+ onBeforeUnmount(() => {
473
+ ancestryObserver.dispose();
474
+ unregister();
475
+ interactions.clear();
476
+ });
246
477
  provide(overlayLayerKey, context);
247
478
  return context;
248
479
  }
@@ -0,0 +1,13 @@
1
+ export declare function isValidDate(value: unknown): value is Date;
2
+ export declare function toLocalDate(value: Date): Date;
3
+ export declare function normalizeDate(value: Date | null | undefined): Date | null;
4
+ export declare function toDateKey(value: Date): string;
5
+ export declare function parseDateKey(value: string): Date | null;
6
+ export declare function compareDates(left: Date, right: Date): number;
7
+ export declare function isSameDate(left: Date | null | undefined, right: Date | null | undefined): boolean;
8
+ export declare function isSameMonth(left: Date, right: Date): boolean;
9
+ export declare function startOfMonth(value: Date): Date;
10
+ export declare function endOfMonth(value: Date): Date;
11
+ export declare function addCalendarDays(value: Date, amount: number): Date;
12
+ export declare function addCalendarMonths(value: Date, amount: number): Date;
13
+ export declare function addCalendarYears(value: Date, amount: number): Date;
@@ -0,0 +1,7 @@
1
+ export type DisabledDateRule = readonly Date[] | ((date: Date) => boolean);
2
+ export interface DateAvailabilityOptions {
3
+ min?: Date;
4
+ max?: Date;
5
+ disabledDates?: DisabledDateRule;
6
+ }
7
+ export declare function isDateUnavailable(date: Date, options: DateAvailabilityOptions): boolean;
@@ -1,5 +1,6 @@
1
1
  export interface ObserveComposedAncestryOptions {
2
2
  deferWhileDisconnected?: boolean;
3
+ notifyOnDisconnect?: boolean;
3
4
  }
4
5
  export declare function getComposedParent(node: Node): Node | null;
5
6
  export declare function getComposedAncestry(node: Node | null | undefined): Node[];
@@ -0,0 +1,2 @@
1
+ export type ElementDirection = 'ltr' | 'rtl';
2
+ export declare function getElementDirection(element: Element): ElementDirection;
@@ -0,0 +1,3 @@
1
+ export declare function normalizeSelectedFiles(files: Iterable<File>, multiple: boolean): File[];
2
+ export declare function haveSameFiles(fileList: FileList | null, files: readonly File[]): boolean;
3
+ export declare function replaceInputFiles(input: HTMLInputElement, files: readonly File[]): boolean;
@@ -0,0 +1,17 @@
1
+ export interface NativeChoiceOption<Value> {
2
+ value: Value;
3
+ }
4
+ export interface NativeSelectChoiceAdapter<Value> {
5
+ commit: (select: HTMLSelectElement, value: Value, defaultValue: Value, applyValue: () => void) => void;
6
+ read: (select: HTMLSelectElement) => Value;
7
+ resolveResetValue: (select: HTMLSelectElement, initialValue: Value) => Value;
8
+ sync: (select: HTMLSelectElement, value: Value, defaultValue: Value) => void;
9
+ }
10
+ interface SingleNativeChoiceAdapterOptions<Value> {
11
+ emptyValue: Value;
12
+ options: () => readonly NativeChoiceOption<Value>[] | undefined;
13
+ }
14
+ export declare function createSingleNativeChoiceAdapter<Value>(options: SingleNativeChoiceAdapterOptions<Value>): NativeSelectChoiceAdapter<Value>;
15
+ export declare function createMultipleNativeChoiceAdapter<Value>(options: () => readonly NativeChoiceOption<Value>[] | undefined): NativeSelectChoiceAdapter<Value[]>;
16
+ export declare function createStringListNativeChoiceAdapter(): NativeSelectChoiceAdapter<string[]>;
17
+ export {};
@@ -0,0 +1,20 @@
1
+ type PointerSessionEndUpdate = 'event' | 'none' | 'pending-pointerup';
2
+ type PointerSessionUpdateMode = 'animation-frame' | 'immediate';
3
+ interface PointerSessionAdapter<TState> {
4
+ endUpdate?: PointerSessionEndUpdate;
5
+ onStart?: (event: PointerEvent, state: TState) => void;
6
+ onStop?: (state: TState) => void;
7
+ onUpdate: (event: PointerEvent, state: TState) => void;
8
+ refreshGeometry?: (state: TState) => boolean;
9
+ updateMode?: PointerSessionUpdateMode;
10
+ }
11
+ interface PointerSessionStart<TState> {
12
+ geometryDirty?: boolean;
13
+ state: TState;
14
+ target: HTMLElement;
15
+ }
16
+ export declare function createPointerSession<TState>(adapter: PointerSessionAdapter<TState>): {
17
+ start: (event: PointerEvent, initialize: () => PointerSessionStart<TState> | undefined) => boolean;
18
+ stop: () => void;
19
+ };
20
+ export {};
@@ -1,5 +1,6 @@
1
+ import { ElementDirection } from './direction.js';
1
2
  export type ScrollAxis = 'x' | 'y';
2
- export type ScrollDirection = 'ltr' | 'rtl';
3
+ export type ScrollDirection = ElementDirection;
3
4
  export interface KeyboardScrollPositionOptions {
4
5
  axis: ScrollAxis;
5
6
  key: string;
@@ -0,0 +1,5 @@
1
+ export interface LabeledOption {
2
+ label: string;
3
+ }
4
+ export type OptionFilter<Option> = (option: Option, searchValue: string) => boolean;
5
+ export declare function filterOptions<Option extends LabeledOption>(options: readonly Option[] | undefined, searchValue: string, filter: OptionFilter<Option> | false | undefined): Option[];
@@ -68,10 +68,10 @@ Use `autoUpdateOptions.animationFrame` sparingly. It checks the reference positi
68
68
  frame and is intended for references moving with CSS transforms or nested floating elements outside
69
69
  their ancestor's scrolling context. The animation-frame loop only runs while positioning is open.
70
70
 
71
- `Popover`, `Tooltip`, `DropdownMenu`, `DropdownMenuContent` and `DropdownMenuSubContent` accept the
72
- same `flipOptions` and `autoUpdateOptions` objects. On the data-driven `DropdownMenu`, the options
73
- also apply to its open submenus. Each open floating element using `animationFrame: true` runs its own
74
- animation-frame loop.
71
+ `HoverCard`, `Popover`, `Tooltip`, `DropdownMenu`, `DropdownMenuContent` and
72
+ `DropdownMenuSubContent` accept the same `flipOptions` and `autoUpdateOptions` objects. On the
73
+ data-driven `DropdownMenu`, the options also apply to its open submenus. Each open floating element
74
+ using `animationFrame: true` runs its own animation-frame loop.
75
75
 
76
76
  The return value contains readonly `actualPlacement`, `floatingStyle`, `arrowStyle` and
77
77
  `isPositioned` refs, plus an async `update()` method for content-driven layout changes.
@@ -92,6 +92,9 @@ for keyboard handling, focus management, roles, labels, outside interaction and
92
92
  coordinates the trigger and floating content, so a close delay started when the pointer leaves the
93
93
  trigger is cancelled when the pointer enters the content.
94
94
 
95
+ `HoverCard` composes this behavior with positioning, Teleport and styled content. Use the composable
96
+ directly when custom markup or a different visual treatment is required.
97
+
95
98
  ```vue
96
99
  <template>
97
100
  <a ref="reference" href="/people/ada" v-bind="triggerProps">Ada Lovelace</a>