@zag-js/popover 0.9.2 → 0.10.1

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.
@@ -168,6 +168,7 @@ function machine(userContext) {
168
168
  trap = createFocusTrap(el, {
169
169
  escapeDeactivates: false,
170
170
  allowOutsideClick: true,
171
+ preventScroll: true,
171
172
  returnFocusOnDeactivate: true,
172
173
  document: dom.getDoc(ctx2),
173
174
  fallbackFocus: el,
@@ -202,14 +203,14 @@ function machine(userContext) {
202
203
  },
203
204
  setInitialFocus(ctx2) {
204
205
  raf(() => {
205
- dom.getInitialFocusEl(ctx2)?.focus();
206
+ dom.getInitialFocusEl(ctx2)?.focus({ preventScroll: true });
206
207
  });
207
208
  },
208
209
  restoreFocusIfNeeded(ctx2, evt) {
209
210
  if (!evt.restoreFocus)
210
211
  return;
211
212
  raf(() => {
212
- dom.getTriggerEl(ctx2)?.focus();
213
+ dom.getTriggerEl(ctx2)?.focus({ preventScroll: true });
213
214
  });
214
215
  },
215
216
  invokeOnOpen(ctx2) {
package/dist/index.js CHANGED
@@ -348,6 +348,7 @@ function machine(userContext) {
348
348
  trap = (0, import_focus_trap.createFocusTrap)(el, {
349
349
  escapeDeactivates: false,
350
350
  allowOutsideClick: true,
351
+ preventScroll: true,
351
352
  returnFocusOnDeactivate: true,
352
353
  document: dom.getDoc(ctx2),
353
354
  fallbackFocus: el,
@@ -382,14 +383,14 @@ function machine(userContext) {
382
383
  },
383
384
  setInitialFocus(ctx2) {
384
385
  (0, import_dom_query3.raf)(() => {
385
- dom.getInitialFocusEl(ctx2)?.focus();
386
+ dom.getInitialFocusEl(ctx2)?.focus({ preventScroll: true });
386
387
  });
387
388
  },
388
389
  restoreFocusIfNeeded(ctx2, evt) {
389
390
  if (!evt.restoreFocus)
390
391
  return;
391
392
  (0, import_dom_query3.raf)(() => {
392
- dom.getTriggerEl(ctx2)?.focus();
393
+ dom.getTriggerEl(ctx2)?.focus({ preventScroll: true });
393
394
  });
394
395
  },
395
396
  invokeOnOpen(ctx2) {
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-KTOPDXGV.mjs";
7
7
  import {
8
8
  machine
9
- } from "./chunk-KWS6ZCAX.mjs";
9
+ } from "./chunk-EDQUDEDS.mjs";
10
10
  import "./chunk-UA4OMIJI.mjs";
11
11
  export {
12
12
  anatomy,
@@ -226,6 +226,7 @@ function machine(userContext) {
226
226
  trap = (0, import_focus_trap.createFocusTrap)(el, {
227
227
  escapeDeactivates: false,
228
228
  allowOutsideClick: true,
229
+ preventScroll: true,
229
230
  returnFocusOnDeactivate: true,
230
231
  document: dom.getDoc(ctx2),
231
232
  fallbackFocus: el,
@@ -260,14 +261,14 @@ function machine(userContext) {
260
261
  },
261
262
  setInitialFocus(ctx2) {
262
263
  (0, import_dom_query2.raf)(() => {
263
- dom.getInitialFocusEl(ctx2)?.focus();
264
+ dom.getInitialFocusEl(ctx2)?.focus({ preventScroll: true });
264
265
  });
265
266
  },
266
267
  restoreFocusIfNeeded(ctx2, evt) {
267
268
  if (!evt.restoreFocus)
268
269
  return;
269
270
  (0, import_dom_query2.raf)(() => {
270
- dom.getTriggerEl(ctx2)?.focus();
271
+ dom.getTriggerEl(ctx2)?.focus({ preventScroll: true });
271
272
  });
272
273
  },
273
274
  invokeOnOpen(ctx2) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  machine
3
- } from "./chunk-KWS6ZCAX.mjs";
3
+ } from "./chunk-EDQUDEDS.mjs";
4
4
  import "./chunk-UA4OMIJI.mjs";
5
5
  export {
6
6
  machine
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/popover",
3
- "version": "0.9.2",
3
+ "version": "0.10.1",
4
4
  "description": "Core logic for the popover widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -17,7 +17,8 @@
17
17
  "repository": "https://github.com/chakra-ui/zag/tree/main/packages/popover",
18
18
  "sideEffects": false,
19
19
  "files": [
20
- "dist/**/*"
20
+ "dist",
21
+ "src"
21
22
  ],
22
23
  "publishConfig": {
23
24
  "access": "public"
@@ -26,17 +27,17 @@
26
27
  "url": "https://github.com/chakra-ui/zag/issues"
27
28
  },
28
29
  "dependencies": {
29
- "focus-trap": "7.4.1",
30
- "@zag-js/anatomy": "0.9.2",
31
- "@zag-js/aria-hidden": "0.9.2",
32
- "@zag-js/core": "0.9.2",
33
- "@zag-js/dom-query": "0.9.2",
34
- "@zag-js/utils": "0.9.2",
35
- "@zag-js/dismissable": "0.9.2",
36
- "@zag-js/tabbable": "0.9.2",
37
- "@zag-js/popper": "0.9.2",
38
- "@zag-js/remove-scroll": "0.9.2",
39
- "@zag-js/types": "0.9.2"
30
+ "focus-trap": "7.4.3",
31
+ "@zag-js/anatomy": "0.10.1",
32
+ "@zag-js/aria-hidden": "0.10.1",
33
+ "@zag-js/core": "0.10.1",
34
+ "@zag-js/dom-query": "0.10.1",
35
+ "@zag-js/utils": "0.10.1",
36
+ "@zag-js/dismissable": "0.10.1",
37
+ "@zag-js/tabbable": "0.10.1",
38
+ "@zag-js/popper": "0.10.1",
39
+ "@zag-js/remove-scroll": "0.10.1",
40
+ "@zag-js/types": "0.10.1"
40
41
  },
41
42
  "devDependencies": {
42
43
  "clean-package": "2.2.0"
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { anatomy } from "./popover.anatomy"
2
+ export { connect } from "./popover.connect"
3
+ export { machine } from "./popover.machine"
4
+ export type { UserDefinedContext as Context } from "./popover.types"
@@ -0,0 +1,14 @@
1
+ import { createAnatomy } from "@zag-js/anatomy"
2
+
3
+ export const anatomy = createAnatomy("popover").parts(
4
+ "arrow",
5
+ "arrowTip",
6
+ "anchor",
7
+ "trigger",
8
+ "positioner",
9
+ "content",
10
+ "title",
11
+ "description",
12
+ "closeTrigger",
13
+ )
14
+ export const parts = anatomy.build()
@@ -0,0 +1,119 @@
1
+ import { dataAttr } from "@zag-js/dom-query"
2
+ import type { PositioningOptions } from "@zag-js/popper"
3
+ import { getPlacementStyles } from "@zag-js/popper"
4
+ import type { NormalizeProps, PropTypes } from "@zag-js/types"
5
+ import { parts } from "./popover.anatomy"
6
+ import { dom } from "./popover.dom"
7
+ import type { Send, State } from "./popover.types"
8
+
9
+ export function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>) {
10
+ const isOpen = state.matches("open")
11
+
12
+ const currentPlacement = state.context.currentPlacement
13
+ const portalled = state.context.currentPortalled
14
+ const rendered = state.context.renderedElements
15
+
16
+ const popperStyles = getPlacementStyles({
17
+ placement: currentPlacement,
18
+ })
19
+
20
+ return {
21
+ /**
22
+ * Whether the popover is portalled
23
+ */
24
+ portalled,
25
+ /**
26
+ * Whether the popover is open
27
+ */
28
+ isOpen,
29
+ /**
30
+ * Function to open the popover
31
+ */
32
+ open() {
33
+ send("OPEN")
34
+ },
35
+ /**
36
+ * Function to close the popover
37
+ */
38
+ close() {
39
+ send("CLOSE")
40
+ },
41
+ /**
42
+ * Function to reposition the popover
43
+ */
44
+ setPositioning(options: Partial<PositioningOptions> = {}) {
45
+ send({ type: "SET_POSITIONING", options })
46
+ },
47
+
48
+ arrowProps: normalize.element({
49
+ id: dom.getArrowId(state.context),
50
+ ...parts.arrow.attrs,
51
+ style: popperStyles.arrow,
52
+ }),
53
+
54
+ arrowTipProps: normalize.element({
55
+ ...parts.arrowTip.attrs,
56
+ style: popperStyles.arrowTip,
57
+ }),
58
+
59
+ anchorProps: normalize.element({
60
+ ...parts.anchor.attrs,
61
+ id: dom.getAnchorId(state.context),
62
+ }),
63
+
64
+ triggerProps: normalize.button({
65
+ ...parts.trigger.attrs,
66
+ type: "button",
67
+ "data-placement": currentPlacement,
68
+ id: dom.getTriggerId(state.context),
69
+ "aria-haspopup": "dialog",
70
+ "aria-expanded": isOpen,
71
+ "data-expanded": dataAttr(isOpen),
72
+ "aria-controls": dom.getContentId(state.context),
73
+ onClick() {
74
+ send("TOGGLE")
75
+ },
76
+ onBlur(event) {
77
+ send({ type: "TRIGGER_BLUR", target: event.relatedTarget })
78
+ },
79
+ }),
80
+
81
+ positionerProps: normalize.element({
82
+ id: dom.getPositionerId(state.context),
83
+ ...parts.positioner.attrs,
84
+ style: popperStyles.floating,
85
+ }),
86
+
87
+ contentProps: normalize.element({
88
+ ...parts.content.attrs,
89
+ id: dom.getContentId(state.context),
90
+ tabIndex: -1,
91
+ role: "dialog",
92
+ hidden: !isOpen,
93
+ "data-expanded": dataAttr(isOpen),
94
+ "aria-labelledby": rendered.title ? dom.getTitleId(state.context) : undefined,
95
+ "aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : undefined,
96
+ "data-placement": currentPlacement,
97
+ }),
98
+
99
+ titleProps: normalize.element({
100
+ ...parts.title.attrs,
101
+ id: dom.getTitleId(state.context),
102
+ }),
103
+
104
+ descriptionProps: normalize.element({
105
+ ...parts.description.attrs,
106
+ id: dom.getDescriptionId(state.context),
107
+ }),
108
+
109
+ closeTriggerProps: normalize.button({
110
+ ...parts.closeTrigger.attrs,
111
+ id: dom.getCloseTriggerId(state.context),
112
+ type: "button",
113
+ "aria-label": "close",
114
+ onClick() {
115
+ send("REQUEST_CLOSE")
116
+ },
117
+ }),
118
+ }
119
+ }
@@ -0,0 +1,39 @@
1
+ import { createScope } from "@zag-js/dom-query"
2
+ import { getFirstTabbable, getFocusables, getLastTabbable, getTabbables } from "@zag-js/tabbable"
3
+ import { runIfFn } from "@zag-js/utils"
4
+ import type { MachineContext as Ctx } from "./popover.types"
5
+
6
+ export const dom = createScope({
7
+ getActiveEl: (ctx: Ctx) => dom.getDoc(ctx).activeElement,
8
+
9
+ getAnchorId: (ctx: Ctx) => ctx.ids?.anchor ?? `popover:${ctx.id}:anchor`,
10
+ getTriggerId: (ctx: Ctx) => ctx.ids?.trigger ?? `popover:${ctx.id}:trigger`,
11
+ getContentId: (ctx: Ctx) => ctx.ids?.content ?? `popover:${ctx.id}:content`,
12
+ getPositionerId: (ctx: Ctx) => ctx.ids?.positioner ?? `popover:${ctx.id}:popper`,
13
+ getArrowId: (ctx: Ctx) => ctx.ids?.arrow ?? `popover:${ctx.id}:arrow`,
14
+ getTitleId: (ctx: Ctx) => ctx.ids?.title ?? `popover:${ctx.id}:title`,
15
+ getDescriptionId: (ctx: Ctx) => ctx.ids?.description ?? `popover:${ctx.id}:desc`,
16
+ getCloseTriggerId: (ctx: Ctx) => ctx.ids?.closeTrigger ?? `popover:${ctx.id}:close`,
17
+
18
+ getAnchorEl: (ctx: Ctx) => dom.getById(ctx, dom.getAnchorId(ctx)),
19
+ getTriggerEl: (ctx: Ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
20
+ getContentEl: (ctx: Ctx) => dom.getById(ctx, dom.getContentId(ctx)),
21
+ getPositionerEl: (ctx: Ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
22
+ getTitleEl: (ctx: Ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
23
+ getDescriptionEl: (ctx: Ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
24
+
25
+ getFocusableEls: (ctx: Ctx) => getFocusables(dom.getContentEl(ctx)),
26
+ getFirstFocusableEl: (ctx: Ctx) => dom.getFocusableEls(ctx)[0],
27
+
28
+ getDocTabbableEls: (ctx: Ctx) => getTabbables(dom.getDoc(ctx).body),
29
+ getTabbableEls: (ctx: Ctx) => getTabbables(dom.getContentEl(ctx), "if-empty"),
30
+ getFirstTabbableEl: (ctx: Ctx) => getFirstTabbable(dom.getContentEl(ctx), "if-empty"),
31
+ getLastTabbableEl: (ctx: Ctx) => getLastTabbable(dom.getContentEl(ctx), "if-empty"),
32
+
33
+ getInitialFocusEl: (ctx: Ctx) => {
34
+ let el: HTMLElement | null = runIfFn(ctx.initialFocusEl)
35
+ if (!el && ctx.autoFocus) el = dom.getFirstFocusableEl(ctx)
36
+ if (!el) el = dom.getContentEl(ctx)
37
+ return el
38
+ },
39
+ })
@@ -0,0 +1,222 @@
1
+ import { ariaHidden } from "@zag-js/aria-hidden"
2
+ import { createMachine } from "@zag-js/core"
3
+ import { trackDismissableElement } from "@zag-js/dismissable"
4
+ import { nextTick, raf } from "@zag-js/dom-query"
5
+ import { getPlacement } from "@zag-js/popper"
6
+ import { preventBodyScroll } from "@zag-js/remove-scroll"
7
+ import { proxyTabFocus } from "@zag-js/tabbable"
8
+ import { compact, runIfFn } from "@zag-js/utils"
9
+ import { FocusTrap, createFocusTrap } from "focus-trap"
10
+ import { dom } from "./popover.dom"
11
+ import type { MachineContext, MachineState, UserDefinedContext } from "./popover.types"
12
+
13
+ export function machine(userContext: UserDefinedContext) {
14
+ const ctx = compact(userContext)
15
+ return createMachine<MachineContext, MachineState>(
16
+ {
17
+ id: "popover",
18
+ initial: ctx.open ? "open" : "closed",
19
+ context: {
20
+ closeOnInteractOutside: true,
21
+ closeOnEsc: true,
22
+ autoFocus: true,
23
+ modal: false,
24
+ positioning: {
25
+ placement: "bottom",
26
+ ...ctx.positioning,
27
+ },
28
+ currentPlacement: undefined,
29
+ ...ctx,
30
+ renderedElements: {
31
+ title: true,
32
+ description: true,
33
+ },
34
+ },
35
+
36
+ computed: {
37
+ currentPortalled: (ctx) => !!ctx.modal || !!ctx.portalled,
38
+ },
39
+
40
+ watch: {
41
+ open: ["toggleVisibility"],
42
+ },
43
+
44
+ entry: ["checkRenderedElements"],
45
+
46
+ states: {
47
+ closed: {
48
+ on: {
49
+ TOGGLE: {
50
+ target: "open",
51
+ actions: ["invokeOnOpen"],
52
+ },
53
+ OPEN: {
54
+ target: "open",
55
+ actions: ["invokeOnOpen"],
56
+ },
57
+ },
58
+ },
59
+
60
+ open: {
61
+ activities: [
62
+ "trapFocus",
63
+ "preventScroll",
64
+ "hideContentBelow",
65
+ "trackPositioning",
66
+ "trackDismissableElement",
67
+ "proxyTabFocus",
68
+ ],
69
+ entry: ["setInitialFocus"],
70
+ on: {
71
+ CLOSE: {
72
+ target: "closed",
73
+ actions: ["invokeOnClose"],
74
+ },
75
+ REQUEST_CLOSE: {
76
+ target: "closed",
77
+ actions: ["restoreFocusIfNeeded", "invokeOnClose"],
78
+ },
79
+ TOGGLE: {
80
+ target: "closed",
81
+ actions: ["invokeOnClose"],
82
+ },
83
+ SET_POSITIONING: {
84
+ actions: "setPositioning",
85
+ },
86
+ },
87
+ },
88
+ },
89
+ },
90
+ {
91
+ activities: {
92
+ trackPositioning(ctx) {
93
+ ctx.currentPlacement = ctx.positioning.placement
94
+ const anchorEl = dom.getAnchorEl(ctx) ?? dom.getTriggerEl(ctx)
95
+ const getPositionerEl = () => dom.getPositionerEl(ctx)
96
+ return getPlacement(anchorEl, getPositionerEl, {
97
+ ...ctx.positioning,
98
+ defer: true,
99
+ onComplete(data) {
100
+ ctx.currentPlacement = data.placement
101
+ },
102
+ onCleanup() {
103
+ ctx.currentPlacement = undefined
104
+ },
105
+ })
106
+ },
107
+ trackDismissableElement(ctx, _evt, { send }) {
108
+ const getContentEl = () => dom.getContentEl(ctx)
109
+ let restoreFocus = true
110
+ return trackDismissableElement(getContentEl, {
111
+ pointerBlocking: ctx.modal,
112
+ exclude: dom.getTriggerEl(ctx),
113
+ defer: true,
114
+ onEscapeKeyDown(event) {
115
+ ctx.onEscapeKeyDown?.(event)
116
+ if (ctx.closeOnEsc) return
117
+ event.preventDefault()
118
+ },
119
+ onInteractOutside(event) {
120
+ ctx.onInteractOutside?.(event)
121
+ if (event.defaultPrevented) return
122
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu)
123
+ if (!ctx.closeOnInteractOutside) {
124
+ event.preventDefault()
125
+ }
126
+ },
127
+ onPointerDownOutside(event) {
128
+ ctx.onPointerDownOutside?.(event)
129
+ },
130
+ onFocusOutside(event) {
131
+ ctx.onFocusOutside?.(event)
132
+ },
133
+ onDismiss() {
134
+ send({ type: "REQUEST_CLOSE", src: "interact-outside", restoreFocus })
135
+ },
136
+ })
137
+ },
138
+ proxyTabFocus(ctx) {
139
+ if (ctx.modal || !ctx.portalled) return
140
+ const getContentEl = () => dom.getContentEl(ctx)
141
+ return proxyTabFocus(getContentEl, {
142
+ triggerElement: dom.getTriggerEl(ctx),
143
+ defer: true,
144
+ onFocus(el) {
145
+ el.focus({ preventScroll: true })
146
+ },
147
+ })
148
+ },
149
+ hideContentBelow(ctx) {
150
+ if (!ctx.modal) return
151
+ const getElements = () => [dom.getContentEl(ctx), dom.getTriggerEl(ctx)]
152
+ return ariaHidden(getElements, { defer: true })
153
+ },
154
+ preventScroll(ctx) {
155
+ if (!ctx.modal) return
156
+ return preventBodyScroll(dom.getDoc(ctx))
157
+ },
158
+ trapFocus(ctx) {
159
+ if (!ctx.modal) return
160
+ let trap: FocusTrap | undefined
161
+ nextTick(() => {
162
+ const el = dom.getContentEl(ctx)
163
+ if (!el) return
164
+ trap = createFocusTrap(el, {
165
+ escapeDeactivates: false,
166
+ allowOutsideClick: true,
167
+ preventScroll: true,
168
+ returnFocusOnDeactivate: true,
169
+ document: dom.getDoc(ctx),
170
+ fallbackFocus: el,
171
+ initialFocus: runIfFn(ctx.initialFocusEl),
172
+ })
173
+ try {
174
+ trap.activate()
175
+ } catch {}
176
+ })
177
+ return () => trap?.deactivate()
178
+ },
179
+ },
180
+ actions: {
181
+ setPositioning(ctx, evt) {
182
+ const anchorEl = dom.getAnchorEl(ctx) ?? dom.getTriggerEl(ctx)
183
+ const getPositionerEl = () => dom.getPositionerEl(ctx)
184
+ getPlacement(anchorEl, getPositionerEl, {
185
+ ...ctx.positioning,
186
+ ...evt.options,
187
+ defer: true,
188
+ listeners: false,
189
+ })
190
+ },
191
+ checkRenderedElements(ctx) {
192
+ raf(() => {
193
+ Object.assign(ctx.renderedElements, {
194
+ title: !!dom.getTitleEl(ctx),
195
+ description: !!dom.getDescriptionEl(ctx),
196
+ })
197
+ })
198
+ },
199
+ setInitialFocus(ctx) {
200
+ raf(() => {
201
+ dom.getInitialFocusEl(ctx)?.focus({ preventScroll: true })
202
+ })
203
+ },
204
+ restoreFocusIfNeeded(ctx, evt) {
205
+ if (!evt.restoreFocus) return
206
+ raf(() => {
207
+ dom.getTriggerEl(ctx)?.focus({ preventScroll: true })
208
+ })
209
+ },
210
+ invokeOnOpen(ctx) {
211
+ ctx.onOpen?.()
212
+ },
213
+ invokeOnClose(ctx) {
214
+ ctx.onClose?.()
215
+ },
216
+ toggleVisibility(ctx, _evt, { send }) {
217
+ send({ type: ctx.open ? "OPEN" : "CLOSE", src: "controlled" })
218
+ },
219
+ },
220
+ },
221
+ )
222
+ }
@@ -0,0 +1,106 @@
1
+ import type { StateMachine as S } from "@zag-js/core"
2
+ import type { DismissableElementHandlers } from "@zag-js/dismissable"
3
+ import type { PositioningOptions, Placement } from "@zag-js/popper"
4
+ import type { CommonProperties, Context, MaybeElement, RequiredBy } from "@zag-js/types"
5
+
6
+ type ElementIds = Partial<{
7
+ anchor: string
8
+ trigger: string
9
+ content: string
10
+ title: string
11
+ description: string
12
+ closeTrigger: string
13
+ positioner: string
14
+ arrow: string
15
+ }>
16
+
17
+ type PublicContext = DismissableElementHandlers &
18
+ CommonProperties & {
19
+ /**
20
+ * The ids of the elements in the popover. Useful for composition.
21
+ */
22
+ ids?: ElementIds
23
+ /**
24
+ * Whether the popover should be modal. When set to `true`:
25
+ * - interaction with outside elements will be disabled
26
+ * - only popover content will be visible to screen readers
27
+ * - scrolling is blocked
28
+ * - focus is trapped within the popover
29
+ *
30
+ * @default false
31
+ */
32
+ modal?: boolean
33
+ /**
34
+ * Whether the popover is rendered in a portal
35
+ */
36
+ portalled?: boolean
37
+ /**
38
+ * Whether to automatically set focus on the first focusable
39
+ * content within the popover when opened.
40
+ */
41
+ autoFocus?: boolean
42
+ /**
43
+ * The element to focus on when the popover is opened.
44
+ */
45
+ initialFocusEl?: MaybeElement | (() => MaybeElement)
46
+ /**
47
+ * Whether to close the popover when the user clicks outside of the popover.
48
+ */
49
+ closeOnInteractOutside?: boolean
50
+ /**
51
+ * Whether to close the popover when the escape key is pressed.
52
+ */
53
+ closeOnEsc?: boolean
54
+ /**
55
+ * Function invoked when the popover is closed
56
+ */
57
+ onClose?: VoidFunction
58
+ /**
59
+ * Function invoked when the popover is opened
60
+ */
61
+ onOpen?: VoidFunction
62
+ /**
63
+ * The user provided options used to position the popover content
64
+ */
65
+ positioning: PositioningOptions
66
+ /**
67
+ * Whether the popover is open
68
+ */
69
+ open?: boolean
70
+ }
71
+
72
+ export type UserDefinedContext = RequiredBy<PublicContext, "id">
73
+
74
+ type ComputedContext = Readonly<{
75
+ /**
76
+ * @computed
77
+ * The computed value of `portalled`
78
+ */
79
+ currentPortalled: boolean
80
+ }>
81
+
82
+ type PrivateContext = Context<{
83
+ /**
84
+ * @internal
85
+ * The elements that are rendered on mount
86
+ */
87
+ renderedElements: {
88
+ title: boolean
89
+ description: boolean
90
+ }
91
+ /**
92
+ * @internal
93
+ * The computed placement (maybe different from initial placement)
94
+ */
95
+ currentPlacement?: Placement
96
+ }>
97
+
98
+ export type MachineContext = PublicContext & ComputedContext & PrivateContext
99
+
100
+ export type MachineState = {
101
+ value: "open" | "closed"
102
+ }
103
+
104
+ export type State = S.State<MachineContext, MachineState>
105
+
106
+ export type Send = S.Send<S.AnyEventObject>