ropav 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +6 -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 +79 -28
  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 +86 -17
  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 +6 -1
  66. package/dist/components/checkbox/useCheckbox.d.ts +2 -0
  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 +4 -1
  74. package/dist/components/color-picker/index.d.ts +2 -2
  75. package/dist/components/color-picker/index.js +2 -2
  76. package/dist/components/color-picker/types.d.ts +13 -1
  77. package/dist/components/color-swatch/index.d.ts +2 -1
  78. package/dist/components/color-swatch/index.js +2 -1
  79. package/dist/components/color-swatch/types.d.ts +4 -1
  80. package/dist/components/dropdown-menu/dropdown-menu-primitives.d.ts +724 -0
  81. package/dist/components/dropdown-menu/dropdown-menu.d.ts +3 -3
  82. package/dist/components/dropdown-menu/index.d.ts +53 -1
  83. package/dist/components/dropdown-menu/index.js +2 -2
  84. package/dist/components/dropdown-menu/types.d.ts +142 -6
  85. package/dist/components/dropdown-menu/useDropdownMenu.d.ts +11 -3
  86. package/dist/components/dropdown-menu/useDropdownMenuDisclosure.d.ts +5 -3
  87. package/dist/components/dropdown-menu/useDropdownMenuDom.d.ts +2 -1
  88. package/dist/components/dropdown-menu/useDropdownMenuInteractions.d.ts +4 -4
  89. package/dist/components/dropdown-menu/useDropdownMenuPortalPosition.d.ts +19 -0
  90. package/dist/components/dropdown-menu/useDropdownMenuRenderItems.d.ts +14 -2
  91. package/dist/components/field/index.d.ts +2 -1
  92. package/dist/components/field/index.js +2 -2
  93. package/dist/components/field/types.d.ts +4 -1
  94. package/dist/components/floating/index.d.ts +1 -0
  95. package/dist/components/floating/index.js +0 -0
  96. package/dist/components/floating/types.d.ts +31 -0
  97. package/dist/components/floating/useFloatingPosition.d.ts +38 -0
  98. package/dist/components/focus-trap/focus-trap.d.ts +31 -0
  99. package/dist/components/focus-trap/index.d.ts +4 -0
  100. package/dist/components/focus-trap/index.js +3 -0
  101. package/dist/components/focus-trap/types.d.ts +41 -0
  102. package/dist/components/focus-trap/useFocusTrap.d.ts +2 -0
  103. package/dist/components/icon-button/index.d.ts +2 -1
  104. package/dist/components/icon-button/index.js +2 -1
  105. package/dist/components/icon-button/types.d.ts +4 -1
  106. package/dist/components/input/index.d.ts +2 -1
  107. package/dist/components/input/index.js +2 -1
  108. package/dist/components/input/types.d.ts +4 -1
  109. package/dist/components/modal/index.d.ts +2 -1
  110. package/dist/components/modal/index.js +2 -2
  111. package/dist/components/modal/types.d.ts +8 -1
  112. package/dist/components/number-input/index.d.ts +2 -1
  113. package/dist/components/number-input/index.js +2 -2
  114. package/dist/components/number-input/types.d.ts +4 -1
  115. package/dist/components/overlay/index.d.ts +2 -1
  116. package/dist/components/overlay/index.js +2 -1
  117. package/dist/components/overlay/types.d.ts +4 -1
  118. package/dist/components/popover/index.d.ts +2 -2
  119. package/dist/components/popover/index.js +2 -2
  120. package/dist/components/popover/popover.d.ts +2 -2
  121. package/dist/components/popover/types.d.ts +20 -11
  122. package/dist/components/popover/usePopover.d.ts +9 -1
  123. package/dist/components/progress/index.d.ts +2 -2
  124. package/dist/components/progress/index.js +2 -2
  125. package/dist/components/progress/types.d.ts +4 -1
  126. package/dist/components/radio/index.d.ts +2 -1
  127. package/dist/components/radio/index.js +2 -2
  128. package/dist/components/radio/radio.d.ts +8 -3
  129. package/dist/components/radio/types.d.ts +20 -3
  130. package/dist/components/radio/useRadio.d.ts +9 -4
  131. package/dist/components/select/index.d.ts +2 -1
  132. package/dist/components/select/index.js +2 -2
  133. package/dist/components/select/types.d.ts +4 -1
  134. package/dist/components/select/useSelect.d.ts +2 -1
  135. package/dist/components/slider/index.d.ts +2 -2
  136. package/dist/components/slider/index.js +2 -2
  137. package/dist/components/slider/range-slider-tooltip.d.ts +3 -0
  138. package/dist/components/slider/range-slider.d.ts +4 -1
  139. package/dist/components/slider/slider.d.ts +4 -1
  140. package/dist/components/slider/sliderCore.d.ts +4 -4
  141. package/dist/components/slider/types.d.ts +12 -2
  142. package/dist/components/slider/useRangeSlider.d.ts +1 -1
  143. package/dist/components/slider/useSlider.d.ts +1 -1
  144. package/dist/components/switch/index.d.ts +2 -1
  145. package/dist/components/switch/index.js +2 -2
  146. package/dist/components/switch/switch.d.ts +4 -1
  147. package/dist/components/switch/types.d.ts +6 -1
  148. package/dist/components/switch/useSwitch.d.ts +2 -0
  149. package/dist/components/tabs/index.d.ts +2 -1
  150. package/dist/components/tabs/index.js +2 -2
  151. package/dist/components/tabs/types.d.ts +13 -4
  152. package/dist/components/teleport-provider/index.d.ts +2 -0
  153. package/dist/components/teleport-provider/index.js +2 -0
  154. package/dist/components/teleport-provider/teleport-provider.d.ts +21 -0
  155. package/dist/components/teleport-provider/types.d.ts +4 -0
  156. package/dist/components/teleport-provider/useTeleportTarget.d.ts +5 -0
  157. package/dist/components/textarea/index.d.ts +2 -1
  158. package/dist/components/textarea/index.js +2 -2
  159. package/dist/components/textarea/textarea.d.ts +4 -1
  160. package/dist/components/textarea/types.d.ts +6 -1
  161. package/dist/components/textarea/useTextarea.d.ts +1 -0
  162. package/dist/components/toast/index.d.ts +2 -2
  163. package/dist/components/toast/index.js +2 -2
  164. package/dist/components/toast/toast.d.ts +2 -2
  165. package/dist/components/toast/types.d.ts +10 -6
  166. package/dist/components/tooltip/index.d.ts +2 -1
  167. package/dist/components/tooltip/index.js +2 -1
  168. package/dist/components/tooltip/tooltip.d.ts +2 -2
  169. package/dist/components/tooltip/types.d.ts +13 -12
  170. package/dist/components/tooltip/useTooltip.d.ts +13 -3
  171. package/dist/dropdown-menu.css +191 -107
  172. package/dist/dropdown-menu.js +1582 -81
  173. package/dist/field.css +41 -39
  174. package/dist/field.js +40 -16
  175. package/dist/focus-trap.js +80 -0
  176. package/dist/icon-button.css +193 -189
  177. package/dist/icon-button.js +23 -18
  178. package/dist/icon-button2.js +8 -0
  179. package/dist/index.d.ts +4 -0
  180. package/dist/index.js +36 -32
  181. package/dist/input.css +122 -120
  182. package/dist/input.js +47 -34
  183. package/dist/input2.js +9 -0
  184. package/dist/legacy-unlayered.css +5461 -0
  185. package/dist/modal.css +129 -127
  186. package/dist/modal.js +160 -200
  187. package/dist/number-input.css +87 -85
  188. package/dist/number-input.js +61 -17
  189. package/dist/overlay.css +26 -24
  190. package/dist/overlay.js +17 -9
  191. package/dist/overlay2.js +4 -0
  192. package/dist/popover.css +140 -107
  193. package/dist/popover.js +288 -193
  194. package/dist/popover2.js +6 -1
  195. package/dist/progress.css +101 -99
  196. package/dist/progress.js +50 -28
  197. package/dist/radio.css +114 -105
  198. package/dist/radio.js +154 -56
  199. package/dist/select.css +244 -242
  200. package/dist/select.js +92 -47
  201. package/dist/slider.css +1109 -1031
  202. package/dist/slider.js +330 -163
  203. package/dist/styles-api.d.ts +22 -0
  204. package/dist/styles-api.js +49 -0
  205. package/dist/switch.css +120 -108
  206. package/dist/switch.js +89 -33
  207. package/dist/tabs.css +286 -278
  208. package/dist/tabs.js +60 -21
  209. package/dist/teleport-provider.js +15 -0
  210. package/dist/textarea.css +132 -130
  211. package/dist/textarea.js +69 -27
  212. package/dist/toast.css +229 -225
  213. package/dist/toast.js +102 -42
  214. package/dist/tooltip.css +137 -107
  215. package/dist/tooltip.js +180 -228
  216. package/dist/tooltip2.js +8 -0
  217. package/dist/useClickOutside.js +1 -1
  218. package/dist/useFloatingPosition.js +1284 -0
  219. package/dist/useFocusTrap.js +130 -0
  220. package/dist/useTeleportTarget.js +29 -0
  221. package/docs/public-styles-api.md +133 -0
  222. package/docs/public-tokens.md +545 -0
  223. package/package.json +29 -5
  224. package/src/styles/_tokens.scss +33 -28
  225. package/src/styles/_utilities.scss +11 -9
  226. package/src/styles/styles-manifest.json +4125 -0
  227. package/dist/rafScheduler.js +0 -34
package/dist/popover.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import './popover.css';
2
2
  import { t as bem } from "./bem.js";
3
+ import { n as useStylesApi, t as presence } from "./styles-api.js";
3
4
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
4
- import { t as createRafScheduler } from "./rafScheduler.js";
5
- import { VaporTransition, applyVShow, computed, createComponent, createIf, createSlot, defineVaporComponent, extend, isRef, onBeforeUnmount, onMounted, ref, renderEffect, setAttr, setClass, setInsertionState, setProp, setStaticTemplateRef, setStyle, template, unref, useId, useSlots, watch } from "vue";
5
+ import { t as useFocusTrap } from "./useFocusTrap.js";
6
+ import { n as useFloatingPosition, r as useFloatingTarget, t as isElementReference } from "./useFloatingPosition.js";
7
+ import { n as useTeleportTarget } from "./useTeleportTarget.js";
8
+ import { VaporTeleport, VaporTransition, applyVShow, computed, createComponent, createIf, createInvoker, createSlot, createTemplateRefSetter, defineVaporComponent, delegateEvents, extend, isRef, nextTick, ref, renderEffect, setAttr, setDynamicProps, setInsertionState, setStaticTemplateRef, setStyle, template, unref, useAttrs, useId, useSlots, watch } from "vue";
6
9
  //#region src/components/popover/usePopover.ts
7
10
  var DEFAULT_PLACEMENT = "bottom";
8
11
  var DEFAULT_ROLE = "dialog";
@@ -11,51 +14,14 @@ var TARGET_ATTRIBUTES = [
11
14
  "aria-expanded",
12
15
  "aria-haspopup"
13
16
  ];
14
- function isHTMLElement(value) {
15
- return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
16
- }
17
- function getTargetPosition(rect, placement) {
18
- const centerX = rect.left + rect.width / 2;
19
- const centerY = rect.top + rect.height / 2;
20
- const [side, alignment = "center"] = placement.split("-");
21
- const alignedX = alignment === "start" ? rect.left : alignment === "end" ? rect.right : centerX;
22
- const alignedY = alignment === "start" ? rect.top : alignment === "end" ? rect.bottom : centerY;
23
- switch (side) {
24
- case "right": return {
25
- x: rect.right,
26
- y: alignedY
27
- };
28
- case "bottom": return {
29
- x: alignedX,
30
- y: rect.bottom
31
- };
32
- case "left": return {
33
- x: rect.left,
34
- y: alignedY
35
- };
36
- default: return {
37
- x: alignedX,
38
- y: rect.top
39
- };
40
- }
41
- }
42
- function setPixelVar(style, variable, value) {
43
- if (value != null) style[variable] = `${value}px`;
44
- }
45
- function styleOrUndefined(style) {
46
- return Object.keys(style).length > 0 ? style : void 0;
47
- }
48
- function resolveOffsetStyle(offset) {
49
- if (offset == null) return void 0;
50
- const style = {};
51
- if (typeof offset === "number") {
52
- setPixelVar(style, "--_rp-popover-main-axis-offset", offset);
53
- return style;
54
- }
55
- setPixelVar(style, "--_rp-popover-main-axis-offset", offset.mainAxis);
56
- setPixelVar(style, "--_rp-popover-cross-axis-offset", offset.crossAxis);
57
- return styleOrUndefined(style);
58
- }
17
+ var TABBABLE_SELECTOR = [
18
+ "a[href]",
19
+ "button:not([disabled])",
20
+ "input:not([disabled])",
21
+ "select:not([disabled])",
22
+ "textarea:not([disabled])",
23
+ "[tabindex]:not([tabindex=\"-1\"])"
24
+ ].join(",");
59
25
  function addIdReference(currentValue, id) {
60
26
  const ids = (currentValue ?? "").split(/\s+/).filter(Boolean);
61
27
  if (!ids.includes(id)) ids.push(id);
@@ -78,53 +44,72 @@ function applyTargetAttributes(element, snapshot, options) {
78
44
  element.setAttribute("aria-expanded", String(options.expanded));
79
45
  element.setAttribute("aria-haspopup", options.role);
80
46
  }
81
- function resolveTargetElement(target) {
82
- if (!target) return null;
83
- if (typeof target !== "string") return isHTMLElement(target) ? target : null;
84
- if (typeof document === "undefined") return null;
85
- try {
86
- const element = document.querySelector(target);
87
- return isHTMLElement(element) ? element : null;
88
- } catch {
89
- return null;
90
- }
47
+ function isFocusTrapContainer(value) {
48
+ return typeof HTMLElement !== "undefined" && value instanceof HTMLElement || typeof SVGElement !== "undefined" && value instanceof SVGElement;
49
+ }
50
+ function resolveOffsetStyle(offset) {
51
+ if (offset == null) return void 0;
52
+ if (typeof offset === "number") return { "--_rp-popover-main-axis-offset": `${offset}px` };
53
+ const style = {};
54
+ if (offset.mainAxis != null) style["--_rp-popover-main-axis-offset"] = `${offset.mainAxis}px`;
55
+ if (offset.crossAxis != null) style["--_rp-popover-cross-axis-offset"] = `${offset.crossAxis}px`;
56
+ return Object.keys(style).length > 0 ? style : void 0;
91
57
  }
92
58
  function usePopover(props, emitOpenChange) {
93
59
  const slots = useSlots();
60
+ const attrs = useAttrs();
94
61
  const generatedId = useId();
95
62
  const rootRef = ref(null);
96
- const targetElement = ref(null);
97
- const targetPosition = ref(null);
63
+ const contentRef = ref(null);
64
+ const arrowRef = ref(null);
98
65
  const uncontrolledOpen = ref(false);
99
- const positionScheduler = createRafScheduler(updateTargetPosition, () => targetElement.value?.ownerDocument.defaultView);
100
66
  const popoverId = computed(() => props.id ?? `${generatedId}-popover`);
101
67
  const placement = computed(() => props.placement ?? DEFAULT_PLACEMENT);
102
68
  const popoverRole = computed(() => props.role ?? DEFAULT_ROLE);
103
- const isTargetMode = computed(() => props.target != null && props.target !== "");
104
- const hasContent = computed(() => Boolean(slots.content || isTargetMode.value && slots.default));
69
+ const teleportTo = useTeleportTarget(() => props.teleportTo);
70
+ const { isExplicitTarget, reference, resolvedTarget } = useFloatingTarget(() => props.target, rootRef);
71
+ const targetElement = computed(() => isElementReference(resolvedTarget.value) ? resolvedTarget.value : null);
72
+ const hasContent = computed(() => Boolean(slots.content || isExplicitTarget.value && slots.default));
105
73
  const isDisabled = computed(() => Boolean(props.disabled || !hasContent.value));
106
74
  const isOpen = computed(() => props.open ?? uncontrolledOpen.value);
107
75
  const isVisible = computed(() => isOpen.value && !isDisabled.value);
108
76
  const shouldRenderContent = computed(() => !isDisabled.value && (Boolean(props.keepMounted) || isVisible.value));
109
77
  const shouldShowContent = computed(() => !props.keepMounted || isVisible.value);
110
- const shouldWireTarget = computed(() => isTargetMode.value && !isDisabled.value);
111
78
  const ariaLabel = computed(() => props.ariaLabel || void 0);
112
79
  const ariaLabelledby = computed(() => props.ariaLabelledby || void 0);
113
80
  const ariaDescribedby = computed(() => props.ariaDescribedby || void 0);
81
+ const focusTrapContainers = computed(() => {
82
+ const content = contentRef.value;
83
+ if (!content) return null;
84
+ const trigger = targetElement.value ?? rootRef.value;
85
+ return isFocusTrapContainer(trigger) ? [trigger, content] : content;
86
+ });
87
+ const floating = useFloatingPosition({
88
+ reference,
89
+ floating: contentRef,
90
+ arrow: arrowRef,
91
+ open: isVisible,
92
+ placement: () => placement.value,
93
+ strategy: () => props.strategy ?? "absolute",
94
+ offset: () => props.offset,
95
+ flip: () => props.flip !== false,
96
+ shift: () => props.shift !== false,
97
+ collisionPadding: () => props.collisionPadding ?? 8,
98
+ arrowEnabled: () => Boolean(props.arrow),
99
+ restartKey: () => teleportTo.value
100
+ });
101
+ const placementSide = computed(() => floating.actualPlacement.value.split("-")[0]);
114
102
  const rootClass = computed(() => bem("rp-popover", {
115
- [`placement-${placement.value}`]: true,
116
- target: isTargetMode.value,
103
+ [`placement-${floating.actualPlacement.value}`]: true,
104
+ target: isExplicitTarget.value,
117
105
  open: isVisible.value,
118
- disabled: props.disabled
106
+ disabled: props.disabled,
107
+ arrow: props.arrow
108
+ }));
109
+ const contentStyle = computed(() => ({
110
+ ...floating.floatingStyle.value,
111
+ ...resolveOffsetStyle(props.offset)
119
112
  }));
120
- const contentStyle = computed(() => {
121
- const style = { ...resolveOffsetStyle(props.offset) };
122
- if (isTargetMode.value && targetPosition.value) {
123
- setPixelVar(style, "--_rp-popover-target-x", targetPosition.value.x);
124
- setPixelVar(style, "--_rp-popover-target-y", targetPosition.value.y);
125
- }
126
- return styleOrUndefined(style);
127
- });
128
113
  const triggerProps = computed(() => ({
129
114
  "aria-controls": isDisabled.value ? void 0 : popoverId.value,
130
115
  "aria-expanded": isDisabled.value ? void 0 : isVisible.value,
@@ -142,17 +127,37 @@ function usePopover(props, emitOpenChange) {
142
127
  triggerProps: triggerProps.value,
143
128
  ...contentSlotProps.value
144
129
  }));
130
+ let shouldReturnFocus = props.returnFocus !== false;
131
+ const focusTrap = useFocusTrap(focusTrapContainers, {
132
+ ...props.focusTrapOptions,
133
+ initialFocus: () => {
134
+ const initialFocus = props.initialFocus;
135
+ return isRef(initialFocus) ? initialFocus.value ?? void 0 : initialFocus ?? void 0;
136
+ },
137
+ fallbackFocus: () => contentRef.value,
138
+ returnFocusOnDeactivate: props.returnFocus !== false,
139
+ escapeDeactivates: false,
140
+ allowOutsideClick: true
141
+ });
145
142
  function setOpen(nextOpen) {
146
143
  const previousOpen = isOpen.value;
147
144
  if (props.open === void 0) uncontrolledOpen.value = nextOpen;
148
145
  if (previousOpen !== nextOpen) emitOpenChange?.(nextOpen);
149
146
  }
150
147
  function openPopover() {
151
- if (isDisabled.value) return;
152
- setOpen(true);
148
+ if (!isDisabled.value) setOpen(true);
153
149
  }
154
150
  function closePopover() {
151
+ shouldReturnFocus = props.returnFocus !== false;
152
+ setOpen(false);
153
+ }
154
+ function closePopoverWithoutReturnFocus() {
155
+ shouldReturnFocus = false;
156
+ if (props.trapFocus) focusTrap.deactivate({ returnFocus: false });
155
157
  setOpen(false);
158
+ nextTick(() => {
159
+ if (props.trapFocus && isVisible.value) focusTrap.activate();
160
+ });
156
161
  }
157
162
  function togglePopover() {
158
163
  if (isVisible.value) closePopover();
@@ -166,113 +171,115 @@ function usePopover(props, emitOpenChange) {
166
171
  event.stopPropagation();
167
172
  closePopover();
168
173
  }
169
- function onTargetClick() {
170
- togglePopover();
171
- }
172
- function readTarget() {
173
- return isRef(props.target) ? props.target.value : props.target;
174
- }
175
- function updateTargetPosition() {
176
- if (!isTargetMode.value || !targetElement.value) {
177
- targetPosition.value = null;
178
- return;
179
- }
180
- targetPosition.value = getTargetPosition(targetElement.value.getBoundingClientRect(), placement.value);
181
- }
182
174
  function isEventInsidePopover(event) {
183
175
  const eventTarget = event.target;
184
176
  if (typeof Node === "undefined" || !(eventTarget instanceof Node)) return false;
185
- return Boolean(rootRef.value?.contains(eventTarget) || targetElement.value?.contains(eventTarget));
177
+ return Boolean(rootRef.value?.contains(eventTarget) || contentRef.value?.contains(eventTarget) || targetElement.value?.contains(eventTarget));
178
+ }
179
+ function onCompositeFocusout(event) {
180
+ const nextTarget = event.relatedTarget;
181
+ if (nextTarget instanceof Node && (rootRef.value?.contains(nextTarget) || contentRef.value?.contains(nextTarget) || targetElement.value?.contains(nextTarget))) return;
182
+ const listener = attrs.onFocusout;
183
+ const listeners = Array.isArray(listener) ? listener : [listener];
184
+ for (const current of listeners) if (typeof current === "function") current(event);
186
185
  }
187
186
  function onDocumentClick(event) {
188
187
  if (props.closeOnOutsideClick === false || isEventInsidePopover(event)) return;
189
- closePopover();
188
+ closePopoverWithoutReturnFocus();
189
+ }
190
+ function onDocumentPointerDown(event) {
191
+ if (!props.trapFocus) return;
192
+ if (props.closeOnOutsideClick === false || isEventInsidePopover(event)) return;
193
+ closePopoverWithoutReturnFocus();
190
194
  }
191
195
  function onDocumentKeydown(event) {
196
+ if (props.trapFocus && event.key === "Tab") {
197
+ const containers = [targetElement.value ?? rootRef.value, contentRef.value];
198
+ const tabbables = [];
199
+ for (const container of containers) {
200
+ if (!container) continue;
201
+ if (container instanceof HTMLElement && container.matches(TABBABLE_SELECTOR)) tabbables.push(container);
202
+ tabbables.push(...container.querySelectorAll(TABBABLE_SELECTOR));
203
+ }
204
+ const active = event.target;
205
+ const first = tabbables[0];
206
+ const last = tabbables[tabbables.length - 1];
207
+ if (event.shiftKey && active === first && last) {
208
+ event.preventDefault();
209
+ last.focus();
210
+ return;
211
+ }
212
+ if (!event.shiftKey && active === last && first) {
213
+ event.preventDefault();
214
+ first.focus();
215
+ return;
216
+ }
217
+ }
192
218
  if (props.closeOnEscape === false || event.key !== "Escape") return;
193
219
  closePopover();
194
220
  }
195
- function syncTargetElement() {
196
- positionScheduler.cancel();
197
- const nextTarget = isTargetMode.value ? resolveTargetElement(readTarget()) : null;
198
- if (targetElement.value !== nextTarget) targetElement.value = nextTarget;
199
- if (!nextTarget) {
200
- targetPosition.value = null;
201
- return;
202
- }
203
- }
204
221
  watch(isDisabled, (disabled) => {
205
222
  if (disabled) closePopover();
206
223
  });
207
- watch(() => readTarget(), () => syncTargetElement(), { flush: "post" });
208
- watch([shouldWireTarget, targetElement], ([shouldWire, target], _previous, onCleanup) => {
209
- if (!shouldWire || !target) return;
210
- target.addEventListener("click", onTargetClick);
211
- onCleanup(() => {
212
- target.removeEventListener("click", onTargetClick);
213
- });
224
+ watch([isVisible, () => props.trapFocus], ([visible, trapFocus]) => {
225
+ if (visible && trapFocus) {
226
+ shouldReturnFocus = props.returnFocus !== false;
227
+ focusTrap.activate();
228
+ return;
229
+ }
230
+ focusTrap.deactivate({ returnFocus: shouldReturnFocus && props.returnFocus !== false });
231
+ shouldReturnFocus = props.returnFocus !== false;
232
+ }, {
233
+ flush: "post",
234
+ immediate: true
235
+ });
236
+ watch([isExplicitTarget, targetElement], ([explicit, target], _previous, onCleanup) => {
237
+ if (!explicit || !target) return;
238
+ target.addEventListener("click", onTriggerClick);
239
+ onCleanup(() => target.removeEventListener("click", onTriggerClick));
214
240
  }, { flush: "sync" });
215
241
  watch([
216
- shouldWireTarget,
242
+ isExplicitTarget,
217
243
  targetElement,
218
244
  popoverId,
219
245
  popoverRole,
220
- isVisible
221
- ], ([shouldWire, target], _previous, onCleanup) => {
222
- if (!shouldWire || !target) return;
246
+ isVisible,
247
+ isDisabled
248
+ ], ([explicit, target, id, role, visible, disabled], _previous, onCleanup) => {
249
+ if (!explicit || !target || disabled) return;
223
250
  const snapshot = snapshotAttributes(target);
224
251
  applyTargetAttributes(target, snapshot, {
225
- id: popoverId.value,
226
- expanded: isVisible.value,
227
- role: popoverRole.value
228
- });
229
- onCleanup(() => {
230
- restoreAttributes(target, snapshot);
231
- });
232
- }, { flush: "sync" });
233
- watch([
234
- isVisible,
235
- isTargetMode,
236
- targetElement
237
- ], ([visible, targetMode, target], _previous, onCleanup) => {
238
- const view = target?.ownerDocument.defaultView;
239
- if (!visible || !targetMode || !view) return;
240
- view.addEventListener("resize", positionScheduler.schedule);
241
- view.addEventListener("scroll", positionScheduler.schedule, true);
242
- onCleanup(() => {
243
- view.removeEventListener("resize", positionScheduler.schedule);
244
- view.removeEventListener("scroll", positionScheduler.schedule, true);
245
- positionScheduler.cancel();
252
+ id,
253
+ expanded: visible,
254
+ role
246
255
  });
256
+ onCleanup(() => restoreAttributes(target, snapshot));
247
257
  }, { flush: "sync" });
248
258
  watch(isVisible, (visible, _previous, onCleanup) => {
249
259
  if (!visible || typeof document === "undefined") return;
250
260
  document.addEventListener("click", onDocumentClick, true);
261
+ document.addEventListener("mousedown", onDocumentPointerDown, true);
262
+ document.addEventListener("touchstart", onDocumentPointerDown, true);
251
263
  document.addEventListener("keydown", onDocumentKeydown);
252
264
  onCleanup(() => {
253
265
  document.removeEventListener("click", onDocumentClick, true);
266
+ document.removeEventListener("mousedown", onDocumentPointerDown, true);
267
+ document.removeEventListener("touchstart", onDocumentPointerDown, true);
254
268
  document.removeEventListener("keydown", onDocumentKeydown);
255
269
  });
256
270
  }, {
257
271
  flush: "sync",
258
272
  immediate: true
259
273
  });
260
- watch([
261
- targetElement,
262
- placement,
263
- isVisible
264
- ], () => {
265
- positionScheduler.cancel();
266
- if (isVisible.value) updateTargetPosition();
267
- }, { flush: "sync" });
268
- onMounted(syncTargetElement);
269
- onBeforeUnmount(positionScheduler.cancel);
270
274
  return {
271
275
  rootRef,
276
+ contentRef,
277
+ arrowRef,
272
278
  popoverId,
273
279
  isOpen,
280
+ isDisabled,
274
281
  isVisible,
275
- isTargetMode,
282
+ isTargetMode: isExplicitTarget,
276
283
  popoverRole,
277
284
  ariaLabel,
278
285
  ariaLabelledby,
@@ -284,26 +291,32 @@ function usePopover(props, emitOpenChange) {
284
291
  triggerProps,
285
292
  slotProps,
286
293
  contentSlotProps,
294
+ actualPlacement: floating.actualPlacement,
295
+ placementSide,
296
+ arrowStyle: floating.arrowStyle,
297
+ teleportTo,
287
298
  openPopover,
288
299
  closePopover,
289
300
  togglePopover,
290
- onTriggerKeydown
301
+ onTriggerKeydown,
302
+ onCompositeFocusout
291
303
  };
292
304
  }
293
305
  //#endregion
294
306
  //#region src/components/popover/popover.vue?vue&type=script&setup=true&vapor=true&lang.ts
295
- var t0 = template("<section data-v-13614b6c class=rp-popover__content>");
296
- var t1 = template("<span data-v-13614b6c>", 1);
307
+ var t0 = template("<span data-v-8af57bff class=rp-popover__arrow aria-hidden=true>");
308
+ var t1 = template("<section data-v-8af57bff>");
309
+ var t2 = template("<span data-v-8af57bff>", 1);
310
+ delegateEvents("focusout");
297
311
  //#endregion
298
312
  //#region src/components/popover/popover.vue
299
313
  var popover_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
300
314
  name: "RpPopover",
315
+ inheritAttrs: false,
301
316
  __name: "popover",
302
317
  props: {
303
318
  id: {},
304
- target: {},
305
- placement: { default: "bottom" },
306
- offset: {},
319
+ contentClass: {},
307
320
  open: {
308
321
  type: Boolean,
309
322
  default: void 0
@@ -327,65 +340,147 @@ var popover_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
327
340
  keepMounted: {
328
341
  type: Boolean,
329
342
  default: false
330
- }
343
+ },
344
+ trapFocus: {
345
+ type: Boolean,
346
+ default: false
347
+ },
348
+ initialFocus: { default: null },
349
+ returnFocus: {
350
+ type: Boolean,
351
+ default: true
352
+ },
353
+ focusTrapOptions: { default: () => ({}) },
354
+ target: {},
355
+ placement: { default: "bottom" },
356
+ strategy: { default: "absolute" },
357
+ offset: {},
358
+ flip: {
359
+ type: Boolean,
360
+ default: true
361
+ },
362
+ shift: {
363
+ type: Boolean,
364
+ default: true
365
+ },
366
+ collisionPadding: { default: 8 },
367
+ arrow: {
368
+ type: Boolean,
369
+ default: false
370
+ },
371
+ teleport: {
372
+ type: Boolean,
373
+ default: true
374
+ },
375
+ teleportTo: {},
376
+ classNames: {},
377
+ styles: {}
331
378
  },
332
379
  emits: ["update:open"],
333
380
  setup(__props, { emit: __emit }) {
334
381
  const props = __props;
335
382
  const emit = __emit;
336
- const { rootRef, popoverId, isTargetMode, popoverRole, ariaLabel, ariaLabelledby, ariaDescribedby, shouldRenderContent, shouldShowContent, rootClass, contentStyle, slotProps, contentSlotProps } = usePopover(props, (open) => {
383
+ const { rootRef, contentRef, arrowRef, popoverId, isDisabled, isTargetMode, popoverRole, ariaLabel, ariaLabelledby, ariaDescribedby, shouldRenderContent, shouldShowContent, rootClass, contentStyle, slotProps, contentSlotProps, actualPlacement, placementSide, arrowStyle, teleportTo, onCompositeFocusout } = usePopover(props, (open) => {
337
384
  emit("update:open", open);
338
385
  });
339
- const n12 = t1();
340
- renderEffect(() => setClass(n12, unref(rootClass)));
341
- setInsertionState(n12, null, 0);
386
+ const { getPartAttrs, getRootAttrs } = useStylesApi(props, "root");
387
+ const publicRootAttrs = computed(() => getRootAttrs({
388
+ class: rootClass.value,
389
+ onFocusout: onCompositeFocusout,
390
+ "data-state": slotProps.value.isOpen ? "open" : "closed",
391
+ "data-disabled": presence(isDisabled.value)
392
+ }, {}, ["onFocusout"]));
393
+ const styledTriggerProps = computed(() => {
394
+ const partAttrs = getPartAttrs("trigger");
395
+ return {
396
+ ...slotProps.value.triggerProps,
397
+ ...props.classNames?.trigger !== void 0 ? { class: partAttrs.class } : {},
398
+ ...props.styles?.trigger !== void 0 ? { style: partAttrs.style } : {},
399
+ "data-state": slotProps.value.isOpen ? "open" : "closed",
400
+ "data-disabled": presence(isDisabled.value)
401
+ };
402
+ });
403
+ const contentAttrs = computed(() => ({
404
+ ...getPartAttrs("content", {
405
+ class: "rp-popover__content",
406
+ compatibilityClass: props.contentClass,
407
+ style: contentStyle.value
408
+ }),
409
+ "data-state": slotProps.value.isOpen ? "open" : "closed",
410
+ "data-placement": actualPlacement.value
411
+ }));
412
+ const _setTemplateRef = createTemplateRefSetter();
413
+ const n16 = t2();
414
+ renderEffect(() => setDynamicProps(n16, [publicRootAttrs.value]));
415
+ setInsertionState(n16, null, 0);
342
416
  createIf(() => !unref(isTargetMode), () => {
343
417
  return createSlot("default", {
344
- triggerProps: () => unref(slotProps).triggerProps,
418
+ triggerProps: () => styledTriggerProps.value,
345
419
  isOpen: () => unref(slotProps).isOpen,
346
420
  open: () => unref(slotProps).open,
347
421
  close: () => unref(slotProps).close,
348
422
  toggle: () => unref(slotProps).toggle
349
423
  }, null, 1);
350
424
  });
351
- setInsertionState(n12, null, 1);
352
- createComponent(VaporTransition, {
353
- name: "rp-popover-content",
354
- persisted: ""
355
- }, extend(() => {
356
- return createIf(() => unref(shouldRenderContent), () => {
357
- const n10 = t0();
358
- renderEffect(() => {
359
- setProp(n10, "id", unref(popoverId));
360
- setProp(n10, "role", unref(popoverRole));
361
- setAttr(n10, "aria-label", unref(ariaLabel));
362
- setAttr(n10, "aria-labelledby", unref(ariaLabelledby));
363
- setAttr(n10, "aria-describedby", unref(ariaDescribedby));
364
- setStyle(n10, unref(contentStyle));
365
- });
366
- setInsertionState(n10, null, 0);
367
- createSlot("content", {
368
- isOpen: () => unref(contentSlotProps).isOpen,
369
- open: () => unref(contentSlotProps).open,
370
- close: () => unref(contentSlotProps).close,
371
- toggle: () => unref(contentSlotProps).toggle
372
- }, () => {
373
- return createIf(() => unref(isTargetMode), () => {
374
- return createSlot("default", {
375
- isOpen: () => unref(contentSlotProps).isOpen,
376
- open: () => unref(contentSlotProps).open,
377
- close: () => unref(contentSlotProps).close,
378
- toggle: () => unref(contentSlotProps).toggle
379
- }, null, 1);
380
- }, null, 129);
381
- }, 1);
382
- applyVShow(n10, () => unref(shouldShowContent));
383
- return n10;
384
- }, null, 129);
385
- }, { _: 8 }));
386
- setStaticTemplateRef(n12, rootRef, null, "rootRef");
387
- return n12;
425
+ setInsertionState(n16, null, 1);
426
+ createComponent(VaporTeleport, {
427
+ to: () => unref(teleportTo),
428
+ disabled: () => !__props.teleport
429
+ }, () => {
430
+ return createComponent(VaporTransition, {
431
+ name: "rp-popover-content",
432
+ persisted: ""
433
+ }, extend(() => {
434
+ return createIf(() => unref(shouldRenderContent), () => {
435
+ const n13 = t1();
436
+ renderEffect(() => setDynamicProps(n13, [
437
+ { id: unref(popoverId) },
438
+ contentAttrs.value,
439
+ {
440
+ role: unref(popoverRole),
441
+ "aria-label": unref(ariaLabel),
442
+ "aria-labelledby": unref(ariaLabelledby),
443
+ "aria-describedby": unref(ariaDescribedby),
444
+ "data-side": unref(placementSide),
445
+ tabindex: __props.trapFocus ? -1 : void 0
446
+ }
447
+ ]));
448
+ setInsertionState(n13, null, 0);
449
+ createSlot("content", {
450
+ isOpen: () => unref(contentSlotProps).isOpen,
451
+ open: () => unref(contentSlotProps).open,
452
+ close: () => unref(contentSlotProps).close,
453
+ toggle: () => unref(contentSlotProps).toggle
454
+ }, () => {
455
+ return createIf(() => unref(isTargetMode), () => {
456
+ return createSlot("default", {
457
+ isOpen: () => unref(contentSlotProps).isOpen,
458
+ open: () => unref(contentSlotProps).open,
459
+ close: () => unref(contentSlotProps).close,
460
+ toggle: () => unref(contentSlotProps).toggle
461
+ }, null, 1);
462
+ }, null, 129);
463
+ }, 1);
464
+ setInsertionState(n13, null, 1);
465
+ createIf(() => __props.arrow, () => {
466
+ const n12 = t0();
467
+ _setTemplateRef(n12, arrowRef, null, "arrowRef");
468
+ renderEffect(() => {
469
+ setAttr(n12, "data-side", unref(placementSide));
470
+ setStyle(n12, unref(arrowStyle));
471
+ });
472
+ return n12;
473
+ });
474
+ applyVShow(n13, () => unref(shouldShowContent));
475
+ n13.$evtfocusout = createInvoker((e) => unref(onCompositeFocusout)(e));
476
+ _setTemplateRef(n13, contentRef, null, "contentRef");
477
+ return n13;
478
+ }, null, 129);
479
+ }, { _: 8 }));
480
+ });
481
+ setStaticTemplateRef(n16, rootRef, null, "rootRef");
482
+ return n16;
388
483
  }
389
- }), [["__scopeId", "data-v-13614b6c"]]);
484
+ }), [["__scopeId", "data-v-8af57bff"]]);
390
485
  //#endregion
391
486
  export { popover_default as t };
package/dist/popover2.js CHANGED
@@ -13,5 +13,10 @@ var popoverPlacements = [
13
13
  "left",
14
14
  "left-end"
15
15
  ];
16
+ var popoverParts = [
17
+ "root",
18
+ "trigger",
19
+ "content"
20
+ ];
16
21
  //#endregion
17
- export { popoverPlacements as t };
22
+ export { popoverPlacements as n, popoverParts as t };