@data-slot/popover 0.2.30 → 0.2.31

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.
package/README.md CHANGED
@@ -47,7 +47,12 @@ import { createPopover } from "@data-slot/popover";
47
47
 
48
48
  const popover = createPopover(element, {
49
49
  defaultOpen: false,
50
- position: "bottom",
50
+ side: "bottom",
51
+ align: "center",
52
+ sideOffset: 4,
53
+ alignOffset: 0,
54
+ avoidCollisions: true,
55
+ collisionPadding: 8,
51
56
  closeOnClickOutside: true,
52
57
  closeOnEscape: true,
53
58
  onOpenChange: (open) => console.log(open),
@@ -59,7 +64,13 @@ const popover = createPopover(element, {
59
64
  | Option | Type | Default | Description |
60
65
  |--------|------|---------|-------------|
61
66
  | `defaultOpen` | `boolean` | `false` | Initial open state |
62
- | `position` | `"top" \| "bottom" \| "left" \| "right"` | `"bottom"` | Position relative to trigger |
67
+ | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Preferred side relative to trigger |
68
+ | `align` | `"start" \| "center" \| "end"` | `"center"` | Preferred alignment on the side axis |
69
+ | `sideOffset` | `number` | `4` | Distance from trigger in pixels |
70
+ | `alignOffset` | `number` | `0` | Offset from alignment edge in pixels |
71
+ | `avoidCollisions` | `boolean` | `true` | Flip/shift to stay in viewport |
72
+ | `collisionPadding` | `number` | `8` | Viewport edge padding in pixels |
73
+ | `position` | `"top" \| "bottom" \| "left" \| "right"` | - | Deprecated alias for `side` |
63
74
  | `closeOnClickOutside` | `boolean` | `true` | Close when clicking outside |
64
75
  | `closeOnEscape` | `boolean` | `true` | Close when pressing Escape |
65
76
  | `onOpenChange` | `(open: boolean) => void` | `undefined` | Callback when open state changes |
@@ -102,17 +113,25 @@ Options can also be set via data attributes on the root element. JS options take
102
113
  | Attribute | Type | Default | Description |
103
114
  |-----------|------|---------|-------------|
104
115
  | `data-default-open` | boolean | `false` | Initial open state |
116
+ | `data-side` | string | `"bottom"` | Preferred side |
117
+ | `data-align` | string | `"center"` | Preferred alignment |
118
+ | `data-side-offset` | number | `4` | Distance from trigger (px) |
119
+ | `data-align-offset` | number | `0` | Offset from alignment edge (px) |
120
+ | `data-avoid-collisions` | boolean | `true` | Flip/shift to stay in viewport |
121
+ | `data-collision-padding` | number | `8` | Viewport edge padding (px) |
105
122
  | `data-close-on-click-outside` | boolean | `true` | Close when clicking outside |
106
123
  | `data-close-on-escape` | boolean | `true` | Close when pressing Escape |
107
124
 
108
125
  Boolean attributes: present or `"true"` = true, `"false"` = false, absent = default.
109
126
 
110
- Position is set via `data-position` on the content element:
127
+ Placement can be set on root or content (content takes precedence):
111
128
 
112
129
  ```html
113
- <div data-slot="popover-content" data-position="top">
130
+ <div data-slot="popover-content" data-side="top" data-align="end">
114
131
  ```
115
132
 
133
+ `data-position` is still supported as a deprecated fallback alias for `data-side`.
134
+
116
135
  ```html
117
136
  <!-- Popover that stays open when clicking outside -->
118
137
  <div data-slot="popover" data-close-on-click-outside="false">
@@ -122,7 +141,8 @@ Position is set via `data-position` on the content element:
122
141
 
123
142
  ## Styling
124
143
 
125
- Use `data-state` and `data-position` attributes:
144
+ Popover position is computed in JavaScript and applied as `position: fixed` + inline `top/left`.
145
+ Use `data-state`, `data-side`, and `data-align` for styling/animation:
126
146
 
127
147
  ```css
128
148
  /* Hidden state */
@@ -130,48 +150,35 @@ Use `data-state` and `data-position` attributes:
130
150
  display: none;
131
151
  }
132
152
 
133
- /* Positioning */
134
- [data-slot="popover"] {
135
- position: relative;
136
- }
137
-
138
153
  [data-slot="popover-content"] {
139
- position: absolute;
154
+ position: fixed;
155
+ transition: opacity 0.2s ease-out, transform 0.2s ease-out;
140
156
  }
141
157
 
142
- [data-slot="popover-content"][data-position="top"] {
143
- bottom: 100%;
144
- left: 50%;
145
- transform: translateX(-50%);
158
+ [data-slot="popover-content"][hidden][data-side="top"] {
159
+ transform: translateY(4px);
146
160
  }
147
-
148
- [data-slot="popover-content"][data-position="bottom"] {
149
- top: 100%;
150
- left: 50%;
151
- transform: translateX(-50%);
161
+ [data-slot="popover-content"][hidden][data-side="bottom"] {
162
+ transform: translateY(-4px);
152
163
  }
153
-
154
- [data-slot="popover-content"][data-position="left"] {
155
- right: 100%;
156
- top: 50%;
157
- transform: translateY(-50%);
164
+ [data-slot="popover-content"][hidden][data-side="left"] {
165
+ transform: translateX(4px);
158
166
  }
159
-
160
- [data-slot="popover-content"][data-position="right"] {
161
- left: 100%;
162
- top: 50%;
163
- transform: translateY(-50%);
167
+ [data-slot="popover-content"][hidden][data-side="right"] {
168
+ transform: translateX(-4px);
164
169
  }
165
170
  ```
166
171
 
167
172
  With Tailwind:
168
173
 
169
174
  ```html
170
- <div data-slot="popover" class="relative">
175
+ <div data-slot="popover">
171
176
  <button data-slot="popover-trigger">Open</button>
172
- <div
173
- data-slot="popover-content"
174
- class="absolute top-full left-1/2 -translate-x-1/2 mt-2 bg-white shadow-lg rounded-lg p-4 hidden data-[state=open]:block"
177
+ <div
178
+ data-slot="popover-content"
179
+ data-side="bottom"
180
+ data-align="start"
181
+ class="fixed bg-white shadow-lg rounded-lg p-4 transition data-[state=closed]:opacity-0"
175
182
  >
176
183
  Content
177
184
  </div>
@@ -228,7 +235,11 @@ element.dispatchEvent(
228
235
 
229
236
  #### Deprecated Shapes
230
237
 
231
- The following shape is deprecated and will be removed in v1.0:
238
+ The following shapes are deprecated and will be removed in the next major release:
239
+
240
+ - `popover:set` detail `{ value: boolean }` (use `{ open: boolean }`)
241
+ - `position` option (use `side`)
242
+ - `data-position` attribute (use `data-side`)
232
243
 
233
244
  ```javascript
234
245
  // Deprecated: { value: boolean }
@@ -237,9 +248,8 @@ element.dispatchEvent(
237
248
  );
238
249
  ```
239
250
 
240
- Use `{ open: boolean }` instead.
251
+ Use the replacements listed above.
241
252
 
242
253
  ## License
243
254
 
244
255
  MIT
245
-
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=(e,t)=>e.querySelector(`[data-slot="${t}"]`),t=(e,t)=>[...e.querySelectorAll(`[data-slot="${t}"]`)],n=new WeakMap;function r(e,t,r){if(typeof process<`u`&&process.env?.NODE_ENV===`production`)return;let i=n.get(e);i||(i=new Set,n.set(e,i)),!i.has(t)&&(i.add(t),console.warn(`[@data-slot] ${r}`))}function i(e){let t=`data-${e.replace(/([A-Z])/g,`-$1`).toLowerCase()}`,n=`data-${e}`;return t===n?[t]:[t,n]}function a(e,t){for(let n of i(t))if(e.hasAttribute(n))return e.getAttribute(n);return null}function o(e,t){return i(t).some(t=>e.hasAttribute(t))}const s=new Set([``,`true`,`1`,`yes`]),c=new Set([`false`,`0`,`no`]);function l(e,t){if(!o(e,t))return;let n=a(e,t);if(n===null)return;let i=n.toLowerCase();if(s.has(i))return!0;if(c.has(i))return!1;r(e,t,`Invalid boolean value "${n}" for data-${t}. Expected: true/false/1/0/yes/no or empty.`)}function u(e,t,n){let i=a(e,t);if(i!==null){if(n.includes(i))return i;r(e,t,`Invalid value "${i}" for data-${t}. Expected one of: ${n.join(`, `)}.`)}}const d=new WeakMap,f=Symbol.for(`data-slot.portal-owner`),p=e=>e[f]??d.get(e);function m(e,t){return h(e,t,new Set)}function h(e,t,n){if(!t)return!1;let r=t instanceof Element?t:t.parentElement;if(!r)return!1;if(e.contains(r))return!0;let i=r;for(;i;){let t=p(i);if(t&&!n.has(t)&&(n.add(t),h(e,t,n)))return!0;i=i.parentElement}return!1}let g=0;const _=(e,t)=>e.id||=`${t}-${++g}`,v=(e,t,n)=>{n===null?e.removeAttribute(`aria-${t}`):e.setAttribute(`aria-${t}`,String(n))};function y(e,t,n,r){return e.addEventListener(t,n,r),()=>e.removeEventListener(t,n,r)}const b=(e,t,n)=>e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:n})),x=[`top`,`bottom`,`left`,`right`],S=`a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])`;function C(t,n={}){let r=e(t,`popover-trigger`),i=e(t,`popover-content`),a=e(t,`popover-close`);if(!r||!i)throw Error(`Popover requires trigger and content slots`);let o=n.defaultOpen??l(t,`defaultOpen`)??!1,s=n.onOpenChange,c=n.closeOnClickOutside??l(t,`closeOnClickOutside`)??!0,d=n.closeOnEscape??l(t,`closeOnEscape`)??!0,f=n.position??u(i,`position`,x)??u(t,`position`,x)??`bottom`,p=o,h=[],g=null,C=!1,w=()=>{C&&(i.removeAttribute(`tabindex`),C=!1)},T=()=>{let e=i.querySelector(`[autofocus]`);if(e)return e.focus();let t=i.querySelector(S);if(t)return t.focus();i.getAttribute(`tabindex`)||(i.setAttribute(`tabindex`,`-1`),C=!0),i.focus()},E=_(i,`popover-content`);r.setAttribute(`aria-haspopup`,`dialog`),r.setAttribute(`aria-controls`,E),i.setAttribute(`data-position`,f);let D=e=>{p!==e&&(e&&(g=document.activeElement),p=e,v(r,`expanded`,p),i.hidden=!p,t.setAttribute(`data-state`,p?`open`:`closed`),i.setAttribute(`data-state`,p?`open`:`closed`),b(t,`popover:change`,{open:p}),s?.(p),e?requestAnimationFrame(T):(w(),requestAnimationFrame(()=>{g&&g.isConnected?g.focus():r.focus(),g=null})))};v(r,`expanded`,p),i.hidden=!p,t.setAttribute(`data-state`,p?`open`:`closed`),i.setAttribute(`data-state`,p?`open`:`closed`),o&&requestAnimationFrame(T),h.push(y(r,`click`,()=>D(!p))),a&&h.push(y(a,`click`,()=>D(!1))),c&&h.push(y(document,`pointerdown`,e=>{if(!p)return;let n=e.target;m(t,n)||D(!1)})),d&&h.push(y(document,`keydown`,e=>{p&&e.key===`Escape`&&(e.preventDefault(),D(!1))})),h.push(y(t,`popover:set`,e=>{let t=e.detail,n;t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`&&D(n)}));let O={open:()=>D(!0),close:()=>D(!1),toggle:()=>D(!p),get isOpen(){return p},destroy:()=>{h.forEach(e=>e()),h.length=0,w()}};return O}const w=new WeakSet;function T(e=document){let n=[];for(let r of t(e,`popover`)){if(w.has(r))continue;w.add(r),n.push(C(r))}return n}exports.create=T,exports.createPopover=C;
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`@data-slot/core`)),l=[`top`,`right`,`bottom`,`left`],u=[`start`,`center`,`end`],d=`a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])`;function f(e,t={}){let n=(0,c.getPart)(e,`popover-trigger`),r=(0,c.getPart)(e,`popover-content`),i=(0,c.getPart)(e,`popover-close`);if(!n||!r)throw Error(`Popover requires trigger and content slots`);let a=t.defaultOpen??(0,c.getDataBool)(e,`defaultOpen`)??!1,o=t.onOpenChange,s=t.closeOnClickOutside??(0,c.getDataBool)(e,`closeOnClickOutside`)??!0,f=t.closeOnEscape??(0,c.getDataBool)(e,`closeOnEscape`)??!0,p=t.position??(0,c.getDataEnum)(r,`position`,l)??(0,c.getDataEnum)(e,`position`,l),m=t.side??(0,c.getDataEnum)(r,`side`,l)??(0,c.getDataEnum)(e,`side`,l)??p??`bottom`,h=t.align??(0,c.getDataEnum)(r,`align`,u)??(0,c.getDataEnum)(e,`align`,u)??`center`,g=t.sideOffset??(0,c.getDataNumber)(r,`sideOffset`)??(0,c.getDataNumber)(e,`sideOffset`)??4,_=t.alignOffset??(0,c.getDataNumber)(r,`alignOffset`)??(0,c.getDataNumber)(e,`alignOffset`)??0,v=t.avoidCollisions??(0,c.getDataBool)(r,`avoidCollisions`)??(0,c.getDataBool)(e,`avoidCollisions`)??!0,y=t.collisionPadding??(0,c.getDataNumber)(r,`collisionPadding`)??(0,c.getDataNumber)(e,`collisionPadding`)??8,b=a,x=[],S=null,C=!1,w=()=>{C&&(r.removeAttribute(`tabindex`),C=!1)},T=()=>{let e=r.querySelector(`[autofocus]`);if(e)return e.focus();let t=r.querySelector(d);if(t)return t.focus();r.getAttribute(`tabindex`)||(r.setAttribute(`tabindex`,`-1`),C=!0),r.focus()},E=(0,c.ensureId)(r,`popover-content`);n.setAttribute(`aria-haspopup`,`dialog`),n.setAttribute(`aria-controls`,E),r.setAttribute(`data-side`,m),r.setAttribute(`data-align`,h),r.setAttribute(`data-position`,m);let D=()=>{let t=e.ownerDocument.defaultView??window,i=n.getBoundingClientRect(),a=r.getBoundingClientRect(),o=(0,c.computeFloatingPosition)({anchorRect:i,contentRect:a,side:m,align:h,sideOffset:g,alignOffset:_,avoidCollisions:v,collisionPadding:y});r.style.position=`absolute`,r.style.top=`${o.y+t.scrollY}px`,r.style.left=`${o.x+t.scrollX}px`,r.style.margin=`0`,r.setAttribute(`data-side`,o.side),r.setAttribute(`data-align`,o.align),r.setAttribute(`data-position`,o.side)},O=(0,c.createPositionSync)({observedElements:[n,r],isActive:()=>b,ancestorScroll:!1,onUpdate:D}),k=t=>{b!==t&&(t&&(S=document.activeElement),b=t,(0,c.setAria)(n,`expanded`,b),(0,c.emit)(e,`popover:change`,{open:b}),o?.(b),t?(r.hidden=!1,e.setAttribute(`data-state`,`open`),r.setAttribute(`data-state`,`open`),D(),O.start(),O.update(),requestAnimationFrame(T)):(O.stop(),r.hidden=!0,e.setAttribute(`data-state`,`closed`),r.setAttribute(`data-state`,`closed`),w(),requestAnimationFrame(()=>{S&&S.isConnected?S.focus():n.focus(),S=null})))};(0,c.setAria)(n,`expanded`,b),r.hidden=!b,e.setAttribute(`data-state`,b?`open`:`closed`),r.setAttribute(`data-state`,b?`open`:`closed`),a&&(D(),O.start(),O.update(),requestAnimationFrame(T)),x.push((0,c.on)(n,`click`,()=>k(!b))),i&&x.push((0,c.on)(i,`click`,()=>k(!1))),x.push((0,c.createDismissLayer)({root:e,isOpen:()=>b,onDismiss:()=>k(!1),closeOnClickOutside:s,closeOnEscape:f})),x.push((0,c.on)(e,`popover:set`,e=>{let t=e.detail,n;t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`&&k(n)}));let A={open:()=>k(!0),close:()=>k(!1),toggle:()=>k(!b),get isOpen(){return b},destroy:()=>{O.stop(),x.forEach(e=>e()),x.length=0,w()}};return A}const p=new WeakSet;function m(e=document){let t=[];for(let n of(0,c.getRoots)(e,`popover`)){if(p.has(n))continue;p.add(n),t.push(f(n))}return t}exports.create=m,exports.createPopover=f;
package/dist/index.d.cts CHANGED
@@ -1,10 +1,31 @@
1
1
  //#region src/index.d.ts
2
- type PopoverPosition = "top" | "bottom" | "left" | "right";
2
+ type PopoverSide = "top" | "right" | "bottom" | "left";
3
+ type PopoverAlign = "start" | "center" | "end";
4
+ /**
5
+ * @deprecated Use `PopoverSide` and `side` option instead.
6
+ * Kept for backward compatibility and planned for removal in the next major.
7
+ */
8
+ type PopoverPosition = PopoverSide;
3
9
  interface PopoverOptions {
4
10
  /** Initial open state */
5
11
  defaultOpen?: boolean;
6
- /** Position of popover relative to trigger */
12
+ /**
13
+ * @deprecated Use `side` instead.
14
+ * TODO(next-major): remove `position` option support and migrate callers to `side`.
15
+ */
7
16
  position?: PopoverPosition;
17
+ /** The preferred side of the trigger to render against. @default "bottom" */
18
+ side?: PopoverSide;
19
+ /** The preferred alignment against the trigger. @default "center" */
20
+ align?: PopoverAlign;
21
+ /** The distance in pixels from the trigger. @default 4 */
22
+ sideOffset?: number;
23
+ /** Offset in pixels from the alignment edge. @default 0 */
24
+ alignOffset?: number;
25
+ /** When true, flips/shifts content to avoid viewport collisions. @default true */
26
+ avoidCollisions?: boolean;
27
+ /** Viewport padding used when avoiding collisions. @default 8 */
28
+ collisionPadding?: number;
8
29
  /** Callback when open state changes */
9
30
  onOpenChange?: (open: boolean) => void;
10
31
  /** Close when clicking outside */
@@ -45,4 +66,4 @@ declare function createPopover(root: Element, options?: PopoverOptions): Popover
45
66
  */
46
67
  declare function create(scope?: ParentNode): PopoverController[];
47
68
  //#endregion
48
- export { PopoverController, PopoverOptions, PopoverPosition, create, createPopover };
69
+ export { PopoverAlign, PopoverController, PopoverOptions, PopoverPosition, PopoverSide, create, createPopover };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,31 @@
1
1
  //#region src/index.d.ts
2
- type PopoverPosition = "top" | "bottom" | "left" | "right";
2
+ type PopoverSide = "top" | "right" | "bottom" | "left";
3
+ type PopoverAlign = "start" | "center" | "end";
4
+ /**
5
+ * @deprecated Use `PopoverSide` and `side` option instead.
6
+ * Kept for backward compatibility and planned for removal in the next major.
7
+ */
8
+ type PopoverPosition = PopoverSide;
3
9
  interface PopoverOptions {
4
10
  /** Initial open state */
5
11
  defaultOpen?: boolean;
6
- /** Position of popover relative to trigger */
12
+ /**
13
+ * @deprecated Use `side` instead.
14
+ * TODO(next-major): remove `position` option support and migrate callers to `side`.
15
+ */
7
16
  position?: PopoverPosition;
17
+ /** The preferred side of the trigger to render against. @default "bottom" */
18
+ side?: PopoverSide;
19
+ /** The preferred alignment against the trigger. @default "center" */
20
+ align?: PopoverAlign;
21
+ /** The distance in pixels from the trigger. @default 4 */
22
+ sideOffset?: number;
23
+ /** Offset in pixels from the alignment edge. @default 0 */
24
+ alignOffset?: number;
25
+ /** When true, flips/shifts content to avoid viewport collisions. @default true */
26
+ avoidCollisions?: boolean;
27
+ /** Viewport padding used when avoiding collisions. @default 8 */
28
+ collisionPadding?: number;
8
29
  /** Callback when open state changes */
9
30
  onOpenChange?: (open: boolean) => void;
10
31
  /** Close when clicking outside */
@@ -45,4 +66,4 @@ declare function createPopover(root: Element, options?: PopoverOptions): Popover
45
66
  */
46
67
  declare function create(scope?: ParentNode): PopoverController[];
47
68
  //#endregion
48
- export { PopoverController, PopoverOptions, PopoverPosition, create, createPopover };
69
+ export { PopoverAlign, PopoverController, PopoverOptions, PopoverPosition, PopoverSide, create, createPopover };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const e=(e,t)=>e.querySelector(`[data-slot="${t}"]`),t=(e,t)=>[...e.querySelectorAll(`[data-slot="${t}"]`)],n=new WeakMap;function r(e,t,r){if(typeof process<`u`&&process.env?.NODE_ENV===`production`)return;let i=n.get(e);i||(i=new Set,n.set(e,i)),!i.has(t)&&(i.add(t),console.warn(`[@data-slot] ${r}`))}function i(e){let t=`data-${e.replace(/([A-Z])/g,`-$1`).toLowerCase()}`,n=`data-${e}`;return t===n?[t]:[t,n]}function a(e,t){for(let n of i(t))if(e.hasAttribute(n))return e.getAttribute(n);return null}function o(e,t){return i(t).some(t=>e.hasAttribute(t))}const s=new Set([``,`true`,`1`,`yes`]),c=new Set([`false`,`0`,`no`]);function l(e,t){if(!o(e,t))return;let n=a(e,t);if(n===null)return;let i=n.toLowerCase();if(s.has(i))return!0;if(c.has(i))return!1;r(e,t,`Invalid boolean value "${n}" for data-${t}. Expected: true/false/1/0/yes/no or empty.`)}function u(e,t,n){let i=a(e,t);if(i!==null){if(n.includes(i))return i;r(e,t,`Invalid value "${i}" for data-${t}. Expected one of: ${n.join(`, `)}.`)}}const d=new WeakMap,f=Symbol.for(`data-slot.portal-owner`),p=e=>e[f]??d.get(e);function m(e,t){return h(e,t,new Set)}function h(e,t,n){if(!t)return!1;let r=t instanceof Element?t:t.parentElement;if(!r)return!1;if(e.contains(r))return!0;let i=r;for(;i;){let t=p(i);if(t&&!n.has(t)&&(n.add(t),h(e,t,n)))return!0;i=i.parentElement}return!1}let g=0;const _=(e,t)=>e.id||=`${t}-${++g}`,v=(e,t,n)=>{n===null?e.removeAttribute(`aria-${t}`):e.setAttribute(`aria-${t}`,String(n))};function y(e,t,n,r){return e.addEventListener(t,n,r),()=>e.removeEventListener(t,n,r)}const b=(e,t,n)=>e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:n})),x=[`top`,`bottom`,`left`,`right`],S=`a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])`;function C(t,n={}){let r=e(t,`popover-trigger`),i=e(t,`popover-content`),a=e(t,`popover-close`);if(!r||!i)throw Error(`Popover requires trigger and content slots`);let o=n.defaultOpen??l(t,`defaultOpen`)??!1,s=n.onOpenChange,c=n.closeOnClickOutside??l(t,`closeOnClickOutside`)??!0,d=n.closeOnEscape??l(t,`closeOnEscape`)??!0,f=n.position??u(i,`position`,x)??u(t,`position`,x)??`bottom`,p=o,h=[],g=null,C=!1,w=()=>{C&&(i.removeAttribute(`tabindex`),C=!1)},T=()=>{let e=i.querySelector(`[autofocus]`);if(e)return e.focus();let t=i.querySelector(S);if(t)return t.focus();i.getAttribute(`tabindex`)||(i.setAttribute(`tabindex`,`-1`),C=!0),i.focus()},E=_(i,`popover-content`);r.setAttribute(`aria-haspopup`,`dialog`),r.setAttribute(`aria-controls`,E),i.setAttribute(`data-position`,f);let D=e=>{p!==e&&(e&&(g=document.activeElement),p=e,v(r,`expanded`,p),i.hidden=!p,t.setAttribute(`data-state`,p?`open`:`closed`),i.setAttribute(`data-state`,p?`open`:`closed`),b(t,`popover:change`,{open:p}),s?.(p),e?requestAnimationFrame(T):(w(),requestAnimationFrame(()=>{g&&g.isConnected?g.focus():r.focus(),g=null})))};v(r,`expanded`,p),i.hidden=!p,t.setAttribute(`data-state`,p?`open`:`closed`),i.setAttribute(`data-state`,p?`open`:`closed`),o&&requestAnimationFrame(T),h.push(y(r,`click`,()=>D(!p))),a&&h.push(y(a,`click`,()=>D(!1))),c&&h.push(y(document,`pointerdown`,e=>{if(!p)return;let n=e.target;m(t,n)||D(!1)})),d&&h.push(y(document,`keydown`,e=>{p&&e.key===`Escape`&&(e.preventDefault(),D(!1))})),h.push(y(t,`popover:set`,e=>{let t=e.detail,n;t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`&&D(n)}));let O={open:()=>D(!0),close:()=>D(!1),toggle:()=>D(!p),get isOpen(){return p},destroy:()=>{h.forEach(e=>e()),h.length=0,w()}};return O}const w=new WeakSet;function T(e=document){let n=[];for(let r of t(e,`popover`)){if(w.has(r))continue;w.add(r),n.push(C(r))}return n}export{T as create,C as createPopover};
1
+ import{computeFloatingPosition as e,createDismissLayer as t,createPositionSync as n,emit as r,ensureId as i,getDataBool as a,getDataEnum as o,getDataNumber as s,getPart as c,getRoots as l,on as u,setAria as d}from"@data-slot/core";const f=[`top`,`right`,`bottom`,`left`],p=[`start`,`center`,`end`],m=`a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])`;function h(l,h={}){let g=c(l,`popover-trigger`),_=c(l,`popover-content`),v=c(l,`popover-close`);if(!g||!_)throw Error(`Popover requires trigger and content slots`);let y=h.defaultOpen??a(l,`defaultOpen`)??!1,b=h.onOpenChange,x=h.closeOnClickOutside??a(l,`closeOnClickOutside`)??!0,S=h.closeOnEscape??a(l,`closeOnEscape`)??!0,C=h.position??o(_,`position`,f)??o(l,`position`,f),w=h.side??o(_,`side`,f)??o(l,`side`,f)??C??`bottom`,T=h.align??o(_,`align`,p)??o(l,`align`,p)??`center`,E=h.sideOffset??s(_,`sideOffset`)??s(l,`sideOffset`)??4,D=h.alignOffset??s(_,`alignOffset`)??s(l,`alignOffset`)??0,O=h.avoidCollisions??a(_,`avoidCollisions`)??a(l,`avoidCollisions`)??!0,k=h.collisionPadding??s(_,`collisionPadding`)??s(l,`collisionPadding`)??8,A=y,j=[],M=null,N=!1,P=()=>{N&&(_.removeAttribute(`tabindex`),N=!1)},F=()=>{let e=_.querySelector(`[autofocus]`);if(e)return e.focus();let t=_.querySelector(m);if(t)return t.focus();_.getAttribute(`tabindex`)||(_.setAttribute(`tabindex`,`-1`),N=!0),_.focus()},I=i(_,`popover-content`);g.setAttribute(`aria-haspopup`,`dialog`),g.setAttribute(`aria-controls`,I),_.setAttribute(`data-side`,w),_.setAttribute(`data-align`,T),_.setAttribute(`data-position`,w);let L=()=>{let t=l.ownerDocument.defaultView??window,n=g.getBoundingClientRect(),r=_.getBoundingClientRect(),i=e({anchorRect:n,contentRect:r,side:w,align:T,sideOffset:E,alignOffset:D,avoidCollisions:O,collisionPadding:k});_.style.position=`absolute`,_.style.top=`${i.y+t.scrollY}px`,_.style.left=`${i.x+t.scrollX}px`,_.style.margin=`0`,_.setAttribute(`data-side`,i.side),_.setAttribute(`data-align`,i.align),_.setAttribute(`data-position`,i.side)},R=n({observedElements:[g,_],isActive:()=>A,ancestorScroll:!1,onUpdate:L}),z=e=>{A!==e&&(e&&(M=document.activeElement),A=e,d(g,`expanded`,A),r(l,`popover:change`,{open:A}),b?.(A),e?(_.hidden=!1,l.setAttribute(`data-state`,`open`),_.setAttribute(`data-state`,`open`),L(),R.start(),R.update(),requestAnimationFrame(F)):(R.stop(),_.hidden=!0,l.setAttribute(`data-state`,`closed`),_.setAttribute(`data-state`,`closed`),P(),requestAnimationFrame(()=>{M&&M.isConnected?M.focus():g.focus(),M=null})))};d(g,`expanded`,A),_.hidden=!A,l.setAttribute(`data-state`,A?`open`:`closed`),_.setAttribute(`data-state`,A?`open`:`closed`),y&&(L(),R.start(),R.update(),requestAnimationFrame(F)),j.push(u(g,`click`,()=>z(!A))),v&&j.push(u(v,`click`,()=>z(!1))),j.push(t({root:l,isOpen:()=>A,onDismiss:()=>z(!1),closeOnClickOutside:x,closeOnEscape:S})),j.push(u(l,`popover:set`,e=>{let t=e.detail,n;t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`&&z(n)}));let B={open:()=>z(!0),close:()=>z(!1),toggle:()=>z(!A),get isOpen(){return A},destroy:()=>{R.stop(),j.forEach(e=>e()),j.length=0,P()}};return B}const g=new WeakSet;function _(e=document){let t=[];for(let n of l(e,`popover`)){if(g.has(n))continue;g.add(n),t.push(h(n))}return t}export{_ as create,h as createPopover};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@data-slot/popover",
3
- "version": "0.2.30",
3
+ "version": "0.2.31",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.cjs",
@@ -24,9 +24,6 @@
24
24
  "scripts": {
25
25
  "build": "tsdown"
26
26
  },
27
- "devDependencies": {
28
- "@data-slot/core": "workspace:*"
29
- },
30
27
  "repository": {
31
28
  "type": "git",
32
29
  "url": "https://github.com/bejamas/data-slot",
@@ -39,5 +36,8 @@
39
36
  "vanilla",
40
37
  "data-slot"
41
38
  ],
42
- "license": "MIT"
39
+ "license": "MIT",
40
+ "dependencies": {
41
+ "@data-slot/core": "workspace:*"
42
+ }
43
43
  }