@ulu/frontend-vue 0.6.22 → 0.6.24

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 (71) hide show
  1. package/dist/components/collapsible/UluAccordion.vue.d.ts +2 -2
  2. package/dist/components/collapsible/UluModal.vue.d.ts +4 -4
  3. package/dist/components/collapsible/UluTabGroup.vue.d.ts +2 -2
  4. package/dist/components/elements/UluAlert.vue.d.ts +2 -2
  5. package/dist/components/elements/UluBadge.vue.d.ts +4 -4
  6. package/dist/components/elements/UluButton.vue.d.ts +10 -10
  7. package/dist/components/elements/UluButtonVerbose.vue.d.ts +4 -4
  8. package/dist/components/elements/UluCaptionedFigure.vue.d.ts +2 -2
  9. package/dist/components/elements/UluCard.vue.d.ts +4 -4
  10. package/dist/components/elements/UluList.vue.d.ts +2 -2
  11. package/dist/components/elements/UluSlider.vue.d.ts +2 -2
  12. package/dist/components/elements/UluTag.vue.d.ts +2 -2
  13. package/dist/components/forms/UluSearchForm.vue.d.ts +2 -2
  14. package/dist/components/layout/UluTitleRail.vue.d.ts +2 -2
  15. package/dist/components/systems/facets/UluFacetsList.vue.d.ts +2 -2
  16. package/dist/components/systems/facets/UluFacetsSearch.vue.d.ts +2 -2
  17. package/dist/components/utils/UluAction.vue.d.ts +2 -2
  18. package/dist/components/visualizations/UluProgressBar.vue.d.ts +2 -2
  19. package/dist/components/visualizations/UluProgressCircle.vue.d.ts +2 -2
  20. package/dist/composables/useUluFloating.d.ts.map +1 -1
  21. package/dist/composables/useUluFloating.js +26 -25
  22. package/dist/index.js +258 -240
  23. package/dist/mcp-data.json +4108 -3442
  24. package/dist/plugins/index.d.ts +2 -1
  25. package/dist/plugins/popovers/UluPopover.vue.d.ts +188 -7
  26. package/dist/plugins/popovers/UluPopover.vue.d.ts.map +1 -1
  27. package/dist/plugins/popovers/UluPopover.vue.js +82 -133
  28. package/dist/plugins/popovers/UluPopoverBase.vue.d.ts +58 -0
  29. package/dist/plugins/popovers/UluPopoverBase.vue.d.ts.map +1 -0
  30. package/dist/plugins/popovers/UluPopoverBase.vue.js +146 -0
  31. package/dist/plugins/popovers/UluTooltipPopover.vue.d.ts +1 -4
  32. package/dist/plugins/popovers/UluTooltipPopover.vue.d.ts.map +1 -1
  33. package/dist/plugins/popovers/UluTooltipPopover.vue.js +24 -45
  34. package/dist/plugins/popovers/index.d.ts +4 -0
  35. package/dist/plugins/popovers/index.d.ts.map +1 -1
  36. package/dist/plugins/popovers/index.js +54 -49
  37. package/dist/plugins/toast/UluToastDisplay.vue.d.ts.map +1 -1
  38. package/dist/plugins/toast/UluToastDisplay.vue.js +8 -7
  39. package/dist/plugins/tour/UluTourContent.vue.d.ts +10 -0
  40. package/dist/plugins/tour/UluTourContent.vue.d.ts.map +1 -0
  41. package/dist/plugins/tour/UluTourContent.vue.js +39 -0
  42. package/dist/plugins/tour/UluTourDisplay.vue.d.ts +100 -0
  43. package/dist/plugins/tour/UluTourDisplay.vue.d.ts.map +1 -0
  44. package/dist/plugins/tour/UluTourDisplay.vue.js +133 -0
  45. package/dist/plugins/tour/UluTourPager.vue.d.ts +3 -0
  46. package/dist/plugins/tour/UluTourPager.vue.d.ts.map +1 -0
  47. package/dist/plugins/tour/UluTourPager.vue.js +31 -0
  48. package/dist/plugins/tour/api.d.ts +52 -0
  49. package/dist/plugins/tour/api.d.ts.map +1 -0
  50. package/dist/plugins/tour/api.js +52 -0
  51. package/dist/plugins/tour/index.d.ts +7 -0
  52. package/dist/plugins/tour/index.d.ts.map +1 -0
  53. package/dist/plugins/tour/index.js +14 -0
  54. package/dist/plugins/tour/useTour.d.ts +8 -0
  55. package/dist/plugins/tour/useTour.d.ts.map +1 -0
  56. package/dist/plugins/tour/useTour.js +8 -0
  57. package/lib/composables/useUluFloating.js +2 -0
  58. package/lib/plugins/index.js +3 -3
  59. package/lib/plugins/popovers/UluPopover.vue +42 -125
  60. package/lib/plugins/popovers/UluPopoverBase.vue +197 -0
  61. package/lib/plugins/popovers/UluTooltipPopover.vue +11 -33
  62. package/lib/plugins/popovers/index.js +15 -5
  63. package/lib/plugins/toast/UluToastDisplay.vue +1 -0
  64. package/lib/plugins/toast/_toast.scss +5 -0
  65. package/lib/plugins/tour/UluTourContent.vue +37 -0
  66. package/lib/plugins/tour/UluTourDisplay.vue +182 -0
  67. package/lib/plugins/tour/UluTourPager.vue +36 -0
  68. package/lib/plugins/tour/api.js +83 -0
  69. package/lib/plugins/tour/index.js +29 -0
  70. package/lib/plugins/tour/useTour.js +10 -0
  71. package/package.json +1 -1
@@ -0,0 +1,133 @@
1
+ import { computed as i, ref as f, watch as S, nextTick as T, onMounted as b, onUnmounted as L, createBlock as l, openBlock as o, Teleport as F, createElementBlock as x, createCommentVNode as $, unref as v, Fragment as I, resolveDynamicComponent as g, normalizeProps as h, mergeProps as s, createSlots as k, withCtx as c, createVNode as w, normalizeStyle as R } from "vue";
2
+ import V from "../../components/collapsible/UluModal.vue.js";
3
+ import D from "../popovers/UluPopoverBase.vue.js";
4
+ import P from "./UluTourPager.vue.js";
5
+ import _ from "./UluTourContent.vue.js";
6
+ import { useTour as M } from "./useTour.js";
7
+ const H = {
8
+ __name: "UluTourDisplay",
9
+ setup(N) {
10
+ const { api: m, state: a } = M(), t = i(() => a.active?.steps[a.stepIndex]), u = f(null), d = f(null), C = i(() => ({
11
+ placement: t.value?.placement || "bottom",
12
+ arrow: !0,
13
+ offset: 8
14
+ })), E = i(() => ({
15
+ ...a.active?.modalProps || {},
16
+ ...t.value?.modalProps || {}
17
+ })), z = i(() => ({
18
+ modifiers: "large",
19
+ ...a.active?.popoverProps || {},
20
+ ...t.value?.popoverProps || {}
21
+ })), r = f(null), p = () => {
22
+ if (u.value) {
23
+ const e = u.value.getBoundingClientRect();
24
+ r.value = {
25
+ top: e.top,
26
+ left: e.left,
27
+ width: e.width,
28
+ height: e.height
29
+ };
30
+ } else
31
+ r.value = null;
32
+ }, B = i(() => {
33
+ if (!r.value) return {};
34
+ const e = r.value;
35
+ return {
36
+ position: "fixed",
37
+ top: 0,
38
+ left: 0,
39
+ width: "100vw",
40
+ height: "100vh",
41
+ pointerEvents: "auto",
42
+ zIndex: 9998,
43
+ background: "rgba(0,0,0,0.5)",
44
+ clipPath: `polygon(
45
+ 0% 0%,
46
+ 100% 0%,
47
+ 100% 100%,
48
+ 0% 100%,
49
+ 0% ${e.top}px,
50
+ ${e.left}px ${e.top}px,
51
+ ${e.left}px ${e.top + e.height}px,
52
+ ${e.left + e.width}px ${e.top + e.height}px,
53
+ ${e.left + e.width}px ${e.top}px,
54
+ ${e.left}px ${e.top}px,
55
+ 0% ${e.top}px
56
+ )`
57
+ };
58
+ });
59
+ return S(t, async (e) => {
60
+ if (e?.target) {
61
+ await T();
62
+ const n = document.querySelector(e.target);
63
+ n ? (u.value = n, d.value && d.value.update(), e.highlight && p()) : console.warn(`Tour target not found: ${e.target}`);
64
+ } else
65
+ u.value = null, r.value = null;
66
+ }, { immediate: !0 }), b(() => {
67
+ window.addEventListener("resize", p), window.addEventListener("scroll", p);
68
+ }), L(() => {
69
+ window.removeEventListener("resize", p), window.removeEventListener("scroll", p);
70
+ }), (e, n) => (o(), l(F, { to: "body" }, [
71
+ v(a).active ? (o(), x(I, { key: 0 }, [
72
+ t.value?.component ? (o(), l(g(t.value.component), h(s({ key: 0 }, t.value.componentProps)), null, 16)) : t.value?.target ? (o(), l(D, s({
73
+ key: 2,
74
+ ref_key: "popoverBase",
75
+ ref: d,
76
+ trigger: u.value,
77
+ config: C.value,
78
+ style: { zIndex: 9999 },
79
+ isOpen: !0,
80
+ onClose: n[1] || (n[1] = (y) => v(m).stop())
81
+ }, z.value), k({
82
+ default: c(() => [
83
+ t.value?.contentComponent ? (o(), l(g(t.value.contentComponent), h(s({ key: 0 }, t.value.componentProps)), null, 16)) : (o(), l(_, {
84
+ key: 1,
85
+ step: t.value,
86
+ "is-modal": !1
87
+ }, null, 8, ["step"]))
88
+ ]),
89
+ _: 2
90
+ }, [
91
+ t.value?.hideFooter ? void 0 : {
92
+ name: "footer",
93
+ fn: c(() => [
94
+ w(P)
95
+ ]),
96
+ key: "0"
97
+ }
98
+ ]), 1040, ["trigger", "config"])) : (o(), l(V, s({
99
+ key: 1,
100
+ modelValue: !0
101
+ }, E.value, {
102
+ onClose: n[0] || (n[0] = (y) => v(m).stop())
103
+ }), k({
104
+ default: c(() => [
105
+ t.value?.contentComponent ? (o(), l(g(t.value.contentComponent), h(s({ key: 0 }, t.value.componentProps)), null, 16)) : (o(), l(_, {
106
+ key: 1,
107
+ step: t.value,
108
+ "is-modal": !0
109
+ }, null, 8, ["step"]))
110
+ ]),
111
+ _: 2
112
+ }, [
113
+ t.value?.hideFooter ? void 0 : {
114
+ name: "footer",
115
+ fn: c(() => [
116
+ w(P)
117
+ ]),
118
+ key: "0"
119
+ }
120
+ ]), 1040)),
121
+ t.value?.target && t.value?.highlight && r.value ? (o(), x("div", {
122
+ key: 3,
123
+ class: "tour-highlight-backdrop",
124
+ style: R(B.value),
125
+ onClick: n[2] || (n[2] = (y) => v(m).stop())
126
+ }, null, 4)) : $("", !0)
127
+ ], 64)) : $("", !0)
128
+ ]));
129
+ }
130
+ };
131
+ export {
132
+ H as default
133
+ };
@@ -0,0 +1,3 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
3
+ //# sourceMappingURL=UluTourPager.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UluTourPager.vue.d.ts","sourceRoot":"","sources":["../../../lib/plugins/tour/UluTourPager.vue"],"names":[],"mappings":"AAqBA;"}
@@ -0,0 +1,31 @@
1
+ import { computed as s, createElementBlock as p, openBlock as u, createVNode as i, unref as n } from "vue";
2
+ import { useTour as c } from "./useTour.js";
3
+ import l from "../../components/elements/UluButton.vue.js";
4
+ const d = { class: "tour-pager layout-flex-justified" }, y = {
5
+ __name: "UluTourPager",
6
+ setup(m) {
7
+ const { api: r, state: e } = c(), o = s(() => e.active && e.stepIndex === e.active.steps.length - 1);
8
+ return s(() => e.active && e.stepIndex === 0), (x, t) => (u(), p("div", d, [
9
+ i(l, {
10
+ onClick: t[0] || (t[0] = (a) => n(r).prev()),
11
+ text: "Previous",
12
+ disabled: n(e).stepIndex === 0,
13
+ icon: "type:previous",
14
+ iconBefore: "",
15
+ small: "",
16
+ secondary: "",
17
+ transparent: ""
18
+ }, null, 8, ["disabled"]),
19
+ i(l, {
20
+ primary: "",
21
+ icon: o.value ? null : "type:next",
22
+ onClick: t[1] || (t[1] = (a) => n(r).next()),
23
+ text: o.value ? "Finish" : "Next",
24
+ small: ""
25
+ }, null, 8, ["icon", "text"])
26
+ ]));
27
+ }
28
+ };
29
+ export {
30
+ y as default
31
+ };
@@ -0,0 +1,52 @@
1
+ export function createApi(state: Object): Object;
2
+ export type TourStep = {
3
+ /**
4
+ * - The CSS selector for the target element. If omitted, step renders as a modal.
5
+ */
6
+ target?: string | undefined;
7
+ /**
8
+ * - The title text for the step.
9
+ */
10
+ title?: string | undefined;
11
+ /**
12
+ * - The content text for the step.
13
+ */
14
+ content?: string | undefined;
15
+ /**
16
+ * - A Vue component to completely replace the modal/popover wrapper and layout.
17
+ */
18
+ component?: Object | undefined;
19
+ /**
20
+ * - A Vue component to replace the step text content, keeping the modal/popover wrappers and default footer.
21
+ */
22
+ contentComponent?: Object | undefined;
23
+ /**
24
+ * - Props to bind to the custom component.
25
+ */
26
+ componentProps?: Object | undefined;
27
+ /**
28
+ * - If true, hides the default tour footer (Next/Back buttons).
29
+ */
30
+ hideFooter?: boolean | undefined;
31
+ /**
32
+ * - Floating UI placement string (e.g. 'bottom', 'right').
33
+ */
34
+ placement?: string | undefined;
35
+ /**
36
+ * - If true, darkens the backdrop around the target element.
37
+ */
38
+ highlight?: boolean | undefined;
39
+ /**
40
+ * - Props to pass to the modal (if target is omitted).
41
+ */
42
+ modalProps?: Object | undefined;
43
+ /**
44
+ * - Props to pass to the popover (if target is present).
45
+ */
46
+ popoverProps?: Object | undefined;
47
+ /**
48
+ * - Async hook called before the step is rendered.
49
+ */
50
+ onEnter?: Function | undefined;
51
+ };
52
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../lib/plugins/tour/api.js"],"names":[],"mappings":"AAuBO,iCAHI,MAAM,GACJ,MAAM,CA6DjB"}
@@ -0,0 +1,52 @@
1
+ import { markRaw as t } from "vue";
2
+ const o = (e) => ({
3
+ /**
4
+ * Starts a new tour
5
+ * @param {Object} tour - The tour configuration object
6
+ * @param {TourStep[]} tour.steps - Array of steps for the tour
7
+ * @param {String} [tour.name] - Optional name for the tour
8
+ * @param {Object} [tour.modalProps] - Global props applied to all modal steps in this tour (can be overridden by step)
9
+ * @param {Object} [tour.popoverProps] - Global props applied to all popover steps in this tour (can be overridden by step)
10
+ */
11
+ async start(n) {
12
+ n?.steps?.length && (await this._runHooks(n.steps[0]), e.active = t(n), e.stepIndex = 0);
13
+ },
14
+ /**
15
+ * Advances the tour to the next step, or stops if it is the last step
16
+ */
17
+ async next() {
18
+ const n = e.active;
19
+ if (n)
20
+ if (e.stepIndex < n.steps.length - 1) {
21
+ const s = e.stepIndex + 1;
22
+ await this._runHooks(n.steps[s]), e.stepIndex = s;
23
+ } else
24
+ this.stop();
25
+ },
26
+ /**
27
+ * Returns the tour to the previous step
28
+ */
29
+ async prev() {
30
+ const n = e.active;
31
+ if (n && e.stepIndex > 0) {
32
+ const s = e.stepIndex - 1;
33
+ await this._runHooks(n.steps[s]), e.stepIndex = s;
34
+ }
35
+ },
36
+ /**
37
+ * Stops and closes the current tour
38
+ */
39
+ stop() {
40
+ e.active = null, e.stepIndex = 0;
41
+ },
42
+ /**
43
+ * Internal method to run asynchronous lifecycle hooks on a step
44
+ * @param {Object} step - The tour step configuration
45
+ */
46
+ async _runHooks(n) {
47
+ n && typeof n.onEnter == "function" && await n.onEnter();
48
+ }
49
+ });
50
+ export {
51
+ o as createApi
52
+ };
@@ -0,0 +1,7 @@
1
+ import { useTour } from './useTour.js';
2
+ export default function install(app: any): void;
3
+ export { useTour };
4
+ export { default as UluTourDisplay } from './UluTourDisplay.vue';
5
+ export { default as UluTourPager } from './UluTourPager.vue';
6
+ export { default as UluTourContent } from './UluTourContent.vue';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/plugins/tour/index.js"],"names":[],"mappings":"AAQA,gDAeC;;;;;wBAjBuB,cAAc"}
@@ -0,0 +1,14 @@
1
+ import { reactive as e } from "vue";
2
+ import u from "./UluTourDisplay.vue.js";
3
+ import { createApi as i } from "./api.js";
4
+ function s(o) {
5
+ const t = e({
6
+ active: null,
7
+ stepIndex: 0
8
+ }), r = i(t);
9
+ o.component("UluTourDisplay", u), o.config.globalProperties.$uluTour = r, o.config.globalProperties.$uluTourState = t, o.provide("uluTour", r), o.provide("uluTourState", t);
10
+ }
11
+ export {
12
+ u as UluTourDisplay,
13
+ s as default
14
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Composable for accessing the Tour API and state
3
+ */
4
+ export function useTour(): {
5
+ api: {};
6
+ state: {};
7
+ };
8
+ //# sourceMappingURL=useTour.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTour.d.ts","sourceRoot":"","sources":["../../../lib/plugins/tour/useTour.js"],"names":[],"mappings":"AAEA;;GAEG;AACH;;;EAIC"}
@@ -0,0 +1,8 @@
1
+ import { useRequiredInject as u } from "../../composables/useRequiredInject.js";
2
+ function r() {
3
+ const t = u("uluTour"), e = u("uluTourState");
4
+ return { api: t, state: e };
5
+ }
6
+ export {
7
+ r as useTour
8
+ };
@@ -38,6 +38,7 @@ export function useUluFloating(trigger, content, config) {
38
38
  const contentArrow = ref(null);
39
39
  const middleware = ref([]);
40
40
  const placementConfig = computed(() => config.value?.placement);
41
+ const strategyConfig = computed(() => config.value?.strategy || 'absolute');
41
42
 
42
43
  const {
43
44
  floatingStyles,
@@ -47,6 +48,7 @@ export function useUluFloating(trigger, content, config) {
47
48
  isPositioned
48
49
  } = useFloating(trigger, content, {
49
50
  placement: placementConfig,
51
+ strategy: strategyConfig,
50
52
  whileElementsMounted: autoUpdate,
51
53
  middleware: middleware,
52
54
  });
@@ -4,9 +4,9 @@
4
4
  * - Used in bundle exports
5
5
  */
6
6
 
7
-
8
7
  export { default as corePlugin } from './core/index.js';
9
- export { default as popoversPlugin, useTooltip, useTooltipFollow } from './popovers/index.js';
8
+ export { default as popoversPlugin, useTooltip, useTooltipFollow, UluPopover, UluPopoverBase, UluTooltipDisplay, UluTooltipPopover } from './popovers/index.js';
10
9
  export { default as modalsPlugin, useModals } from './modals/index.js';
11
10
  export { default as toastPlugin, useToast, UluToast, UluToastDisplay } from "./toast/index.js";
12
- export { default as breakpointsPlugin } from './breakpoints/index.js';
11
+ export { default as breakpointsPlugin } from './breakpoints/index.js';
12
+ export { default as tourPlugin, useTour, UluTourDisplay, UluTourPager, UluTourContent } from './tour/index.js';
@@ -19,143 +19,81 @@
19
19
  {{ triggerText }}
20
20
  </slot>
21
21
  </button>
22
- <span
23
- class="popover"
24
- ref="content"
22
+
23
+ <UluPopoverBase
24
+ ref="popoverBase"
25
+ :trigger="trigger"
26
+ :config="resolvedConfig"
27
+ :isOpen="isOpen"
28
+ :clickOutsideCloses="clickOutsideCloses"
29
+ :directFocus="directFocus"
25
30
  :class="[
26
31
  size ? `popover--${ size }` : '',
27
32
  {
28
- 'popover--no-padding' : noPadding,
29
- 'popover--fixed' : isFixedStrategy,
30
- 'is-active' : isOpen
33
+ 'popover--no-padding' : noPadding
31
34
  },
32
35
  classes.content,
33
36
  ]"
34
37
  :aria-labelledby="triggerId"
35
38
  :id="id"
36
- :style="floatingStyles"
37
- :data-placement="placement"
38
- @keydown.esc="changeTo(false)"
39
- tabindex="-1"
39
+ @close="changeTo(false)"
40
40
  >
41
- <span class="popover__inner">
42
- <slot :isOpen="isOpen" :toggle="toggle" :close="close"/>
43
- </span>
44
- <span v-if="$slots.footer" class="popover__footer">
41
+ <slot :isOpen="isOpen" :toggle="toggle" :close="close"/>
42
+ <template #footer v-if="$slots.footer">
45
43
  <slot name="footer" :close="close"/>
46
- </span>
47
- <span
48
- v-if="resolvedConfig.arrow"
49
- class="popover__arrow"
50
- ref="contentArrow"
51
- :style="arrowStyles"
52
- data-ulu-popover-arrow
53
- ></span>
54
- </span>
44
+ </template>
45
+ </UluPopoverBase>
55
46
  </template>
56
47
  <script setup>
57
- import { ref, computed, unref, nextTick } from "vue";
48
+ import { ref, computed } from "vue";
58
49
  import { useRequiredInject } from "../../composables/useRequiredInject.js";
59
50
  import { POPOVER_OPTIONS_KEY } from "./index.js";
60
51
  import defaults from "./defaults.js";
61
52
  import { newId } from "../../utils/dom.js";
62
- import { useUluFloating } from "../../composables/useUluFloating.js";
53
+ import UluPopoverBase from "./UluPopoverBase.vue";
63
54
 
64
55
  const emit = defineEmits(["toggle"]);
65
56
  const props = defineProps({
66
- /**
67
- * Text for popover button
68
- */
69
57
  triggerText: String,
70
- /**
71
- * Add optional aria-label to button for icons/etc
72
- */
73
58
  triggerAlt: String,
74
- /**
75
- * Disable trigger button
76
- */
77
59
  disabled: Boolean,
78
- /**
79
- * Tooltip text for trigger button
80
- */
81
60
  tooltip: String,
82
- /**
83
- * Popover size (ie large, etc)
84
- */
85
61
  size: String,
86
- /**
87
- * No padding on popover content
88
- */
89
62
  noPadding: Boolean,
90
- /**
91
- * Floating UI config (merged with defaults for popover)
92
- * - See useUluFloating() composable for config API
93
- */
94
63
  config: {
95
64
  type: Object,
96
65
  default: () => ({})
97
66
  },
98
- /**
99
- * Mount this component already open state
100
- */
101
67
  startOpen: Boolean,
102
- /**
103
- * Active class for trigger button
104
- */
105
68
  activeClass: {
106
69
  type: String,
107
70
  default: "is-active"
108
71
  },
109
- /**
110
- * Add custom classes to specific elements
111
- * { trigger, content }
112
- */
113
72
  classes: {
114
73
  type: Object,
115
74
  default: () => ({})
116
75
  },
117
- /**
118
- * Close popover when click is outside
119
- */
120
76
  clickOutsideCloses: {
121
77
  type: Boolean,
122
78
  default: true
123
79
  },
124
80
  /**
125
- * Direct focus when open/closing popover
81
+ * Direct focus when open/closing popover.
82
+ * Overrides UluPopoverBase's default focus management.
126
83
  */
127
- directFocus: {
128
- type: Function,
129
- default: ({ isOpen, content }) => {
130
- if (isOpen) {
131
- content.focus({ preventScroll: true });
132
- }
133
- }
134
- }
84
+ directFocus: Function
135
85
  });
136
86
 
137
87
  const id = newId();
138
88
  const triggerId = newId();
139
89
 
140
- // Inject global options, falling back to the static defaults file.
141
90
  const injectedOptions = useRequiredInject(POPOVER_OPTIONS_KEY);
142
91
  const baseConfig = injectedOptions ? injectedOptions.popover : defaults.popover;
143
-
144
- // Create a plain config object, same as pre-refactor.
145
92
  const resolvedConfig = computed(() => ({ ...baseConfig, ...props.config }));
146
93
 
147
94
  const isOpen = ref(props.startOpen || false);
148
95
  const trigger = ref(null);
149
- const content = ref(null);
150
-
151
- const {
152
- floatingStyles,
153
- placement,
154
- update,
155
- arrowStyles,
156
- contentArrow,
157
- isFixedStrategy
158
- } = useUluFloating(trigger, content, resolvedConfig);
96
+ const popoverBase = ref(null);
159
97
 
160
98
  const toggle = () => {
161
99
  changeTo(!isOpen.value);
@@ -163,49 +101,28 @@
163
101
 
164
102
  const changeTo = (toOpen) => {
165
103
  isOpen.value = toOpen;
166
-
167
- const focusArgs = {
168
- trigger: unref(trigger),
169
- content: unref(content),
170
- isOpen: unref(isOpen)
171
- };
172
- const eventArgs = { isOpen: focusArgs.isOpen };
173
- nextTick(() => {
174
- if (isOpen.value) {
175
- update();
176
- // Push to next event, without this will get triggered by the original click event
177
- window.setTimeout(() => {
178
- addOutsideClick();
179
- props.directFocus(focusArgs);
180
- emit("toggle", eventArgs);
181
- }, 0);
182
- } else {
183
- destroyOutsideClick();
184
- props.directFocus(focusArgs);
185
- emit("toggle", eventArgs);
186
- }
187
- });
104
+ emit("toggle", { isOpen: toOpen });
188
105
  };
189
106
 
190
- let outsideHandler;
191
- const addOutsideClick = () => {
192
- if (props.clickOutsideCloses) {
193
- if (outsideHandler) {
194
- destroyOutsideClick();
195
- }
196
- outsideHandler = event => {
197
- if (content.value && !content.value.contains(event.target)) {
198
- changeTo(false);
199
- }
200
- };
201
- document.addEventListener("click", outsideHandler);
202
- }
203
- };
204
- const destroyOutsideClick = () => {
205
- if (outsideHandler) {
206
- document.removeEventListener("click", outsideHandler);
207
- outsideHandler = null;
208
- }
209
- };
210
107
  const close = () => changeTo(false);
211
- </script>
108
+
109
+ defineExpose({
110
+ /**
111
+ * The reactive internal open/closed state of the popover
112
+ */
113
+ isOpen,
114
+ /**
115
+ * Method to toggle the popover open/closed
116
+ */
117
+ toggle,
118
+ /**
119
+ * Method to force the popover closed
120
+ */
121
+ close,
122
+ /**
123
+ * Method to explicitly set the open state
124
+ * @param {Boolean} toOpen - The desired state
125
+ */
126
+ changeTo
127
+ });
128
+ </script>