@primitiv-ui/web 0.1.54 → 0.1.55

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
@@ -6,7 +6,7 @@ framework and no runtime dependencies beyond
6
6
  server-rendered stack (HTMX, Rails, Django, Laravel, Spring …), and inside
7
7
  React, Vue, Angular or any other framework.
8
8
 
9
- > **Status: published.** Tabs, Accordion, Collapsible and Modal so far. See
9
+ > **Status: published.** Tabs, Accordion, Collapsible, Modal and Popover so far. See
10
10
  > [RFC 0033](../../docs/rfcs/0033-web-components.md) for the design.
11
11
 
12
12
  ## Components
@@ -17,6 +17,7 @@ React, Vue, Angular or any other framework.
17
17
  | Accordion | `primitiv-accordion`, `-item`, `-trigger`, `-content`, `-trigger-icon` | `primitiv-accordion-change` | 0.1.44 |
18
18
  | Collapsible | `primitiv-collapsible`, `-trigger`, `-content`, `-trigger-icon` | `primitiv-collapsible-change` | 0.1.47 |
19
19
  | Modal | `primitiv-modal`, `-trigger`, `-content`, `-title`, `-description`, `-close` | `primitiv-modal-change` | 0.1.54 |
20
+ | Popover | `primitiv-popover`, `-trigger`, `-anchor`, `-content`, `-title`, `-description`, `-close` | `primitiv-popover-change` | 0.1.55 |
20
21
 
21
22
  ## Use it
22
23
 
@@ -49,9 +50,9 @@ downloads it once. `dist/primitiv-web.js` is the alternative: every element in
49
50
  one file. Per-component files ship from 0.1.43.
50
51
 
51
52
  The main entry (`@primitiv-ui/web`, `/tabs`, `/accordion`, `/collapsible`,
52
- `/modal`) exports the classes and `defineTabs(registry?)` /
53
+ `/modal`, `/popover`) exports the classes and `defineTabs(registry?)` /
53
54
  `defineAccordion(registry?)` / `defineCollapsible(registry?)` /
54
- `defineModal(registry?)` with **no side effects**.
55
+ `defineModal(registry?)` / `definePopover(registry?)` with **no side effects**.
55
56
 
56
57
  **Render `hidden` on inactive panels yourself.** Until the module loads, CSS
57
58
  cannot tell which panel is active, so markup that omits it shows every panel.
@@ -154,6 +155,34 @@ on a panel as it becomes active, for lazy loading.
154
155
  press, a `<form method="dialog">` — so `preventDefault()` keeps a dirty form
155
156
  open.
156
157
 
158
+ ### Popover
159
+
160
+ ```html
161
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/cdn/popover.js"></script>
162
+
163
+ <primitiv-popover>
164
+ <primitiv-popover-trigger><button type="button">Share</button></primitiv-popover-trigger>
165
+ <primitiv-popover-content popover="auto">
166
+ <primitiv-popover-title><h2>Share this page</h2></primitiv-popover-title>
167
+ <primitiv-popover-description><p>Anyone with the link can view it.</p></primitiv-popover-description>
168
+ <primitiv-popover-close><button type="button">Done</button></primitiv-popover-close>
169
+ </primitiv-popover-content>
170
+ </primitiv-popover>
171
+ ```
172
+
173
+ - **It is a native `popover="auto"` panel**: the browser supplies the top layer
174
+ and light dismiss. The element adds `role="dialog"` and the trigger's ARIA,
175
+ moves focus into the panel on open, and closes it on Escape with focus back on
176
+ the trigger. Write `popover="auto"` yourself so the panel is hidden before the
177
+ script loads.
178
+ - **No anchor wiring.** The panel is shown with its trigger as its source (or
179
+ the element inside `<primitiv-popover-anchor>`), which makes it the implicit
180
+ anchor, so CSS anchor positioning (`position-area`) places it with no
181
+ `anchor-name` / `position-anchor` pair.
182
+ - **`open` on the root is the state**; the `open` property reads and sets it.
183
+ **Listen with `primitiv-popover-change`** (bubbles, cancelable, `detail: {
184
+ open }`), fired before every user-driven change, a light dismiss included.
185
+
157
186
  **TypeScript** — opt into the tag map so DOM queries return the element classes:
158
187
  `import type {} from "@primitiv-ui/web/tags"` (npm only).
159
188
 
@@ -0,0 +1 @@
1
+ var t=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(",");export{t as a};
package/dist/cdn/modal.js CHANGED
@@ -1 +1 @@
1
- import{a as l,b as i,c as h,d as L,f as M}from"./chunks/chunk-QVNDDONZ.js";var C=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(",");function H({key:n,shiftKey:t,active:e,count:o}){if(n!=="Tab")return null;if(o===0)return{focus:null};let r=o-1;return!t&&e===r?{focus:0}:t&&e===0?{focus:r}:null}function O(n,t){return t.x<n.left||t.x>n.right||t.y<n.top||t.y>n.bottom}var d=class{#e;#t;#n=null;constructor(t,e){this.#e=t,this.#t=e}connect(){if(this.#n)return;this.#n=new AbortController;let{signal:t}=this.#n,e=this.#e;e.addEventListener("close",()=>this.#t.change(!1),{signal:t}),e.addEventListener("cancel",o=>this.#i(o),{signal:t}),e.addEventListener("pointerdown",o=>this.#o(o),{signal:t}),e.addEventListener("keydown",o=>this.#s(o),{signal:t})}disconnect(){this.#n?.abort(),this.#n=null}sync(){let{open:t}=this.#t.state();t&&!this.#e.open?this.#e.showModal():!t&&this.#e.open&&this.#e.close()}#i(t){this.#t.escapeKeyDown?.(t);let e=t.defaultPrevented;t.preventDefault(),e||this.#t.change(!1)}#o(t){let e={x:t.clientX,y:t.clientY};O(this.#e.getBoundingClientRect(),e)&&(this.#t.pointerDownOutside?.(t),t.defaultPrevented||this.#t.change(!1))}#s(t){if(!this.#e.open)return;let e=[...this.#e.querySelectorAll(C)],o=H({key:t.key,shiftKey:t.shiftKey,active:e.indexOf(document.activeElement),count:e.length});o&&(t.preventDefault(),o.focus!==null&&e[o.focus].focus())}};var k="primitiv-modal",w="primitiv-modal-trigger",v="primitiv-modal-content",D="primitiv-modal-title",R="primitiv-modal-description",A="primitiv-modal-close";function p(n,t){return n.childElementCount===1?n.firstElementChild:(h(n,`<${n.localName}> needs exactly one element child (${t}) to decorate.`),null)}function K(n){let t=n.firstElementChild;return n.childElementCount===1&&t instanceof HTMLDialogElement?t:(h(n,`<${v}> needs exactly one <dialog> child to decorate.`),null)}var f=class extends M{#e=null;#t=null;#n=[];#i=[];#o=null;controller={connect:()=>this.#a(),disconnect:()=>this.#c()};reconcileOn=["open"];get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",t)}#s(){return{state:()=>({open:this.open}),change:t=>this.#l(t)}}#l(t){t!==this.open&&(this.announce("primitiv-modal-change",{open:t})?this.open=t:this.#t?.sync())}#a(){this.#o=new AbortController,this.addEventListener("click",t=>this.#d(t),{signal:this.#o.signal}),this.#t?.connect()}#c(){this.#o.abort(),this.#o=null,this.#t?.disconnect(),this.#e&&i(this.#e,"open",null)}#d(t){let e=t.target;this.#n.some(o=>o.contains(e))?this.#l(!0):this.#i.some(o=>o.contains(e))&&this.#l(!1)}#u(t){t!==this.#e&&(this.#t?.disconnect(),t&&i(t,"open",null),this.#e=t,this.#t=t?new d(t,this.#s()):null,this.#t?.connect())}reconcile(){let t=this.open,e=t?"open":"closed",o=this.rootId();i(this,"data-state",e);let[r]=this.parts(v),s=r?K(r):null,[x]=this.parts(D),a=x?p(x,"a heading"):null,[T]=this.parts(R),c=T?p(T,"a <p>"):null;a&&!a.id&&(a.id=`${o}-title`),c&&!c.id&&(c.id=`${o}-description`),s&&(s.id||(s.id=`${o}-content`),i(s,"data-state",e),i(s,"aria-labelledby",a?a.id:null),i(s,"aria-describedby",c?c.id:null)),this.#n=this.#r(w);for(let u of this.#n)i(u,"aria-haspopup","dialog"),i(u,"aria-expanded",String(t)),i(u,"aria-controls",s?s.id:null);this.#i=this.#r(A),this.#u(s),this.#t?.sync()}#r(t){return this.parts(t).flatMap(e=>p(e,"a <button>")??[])}},m=class extends l{},b=class extends l{},E=class extends l{},g=class extends l{},y=class extends l{};function S(n=globalThis.customElements){L(n,[[k,f],[w,m],[v,b],[D,E],[R,g],[A,y]])}S();
1
+ import{a as H}from"./chunks/chunk-PKW6AKXD.js";import{a as l,b as i,c as h,d as M,f as L}from"./chunks/chunk-QVNDDONZ.js";function C({key:n,shiftKey:t,active:e,count:o}){if(n!=="Tab")return null;if(o===0)return{focus:null};let r=o-1;return!t&&e===r?{focus:0}:t&&e===0?{focus:r}:null}function O(n,t){return t.x<n.left||t.x>n.right||t.y<n.top||t.y>n.bottom}var d=class{#e;#t;#n=null;constructor(t,e){this.#e=t,this.#t=e}connect(){if(this.#n)return;this.#n=new AbortController;let{signal:t}=this.#n,e=this.#e;e.addEventListener("close",()=>this.#t.change(!1),{signal:t}),e.addEventListener("cancel",o=>this.#i(o),{signal:t}),e.addEventListener("pointerdown",o=>this.#o(o),{signal:t}),e.addEventListener("keydown",o=>this.#s(o),{signal:t})}disconnect(){this.#n?.abort(),this.#n=null}sync(){let{open:t}=this.#t.state();t&&!this.#e.open?this.#e.showModal():!t&&this.#e.open&&this.#e.close()}#i(t){this.#t.escapeKeyDown?.(t);let e=t.defaultPrevented;t.preventDefault(),e||this.#t.change(!1)}#o(t){let e={x:t.clientX,y:t.clientY};O(this.#e.getBoundingClientRect(),e)&&(this.#t.pointerDownOutside?.(t),t.defaultPrevented||this.#t.change(!1))}#s(t){if(!this.#e.open)return;let e=[...this.#e.querySelectorAll(H)],o=C({key:t.key,shiftKey:t.shiftKey,active:e.indexOf(document.activeElement),count:e.length});o&&(t.preventDefault(),o.focus!==null&&e[o.focus].focus())}};var k="primitiv-modal",w="primitiv-modal-trigger",v="primitiv-modal-content",D="primitiv-modal-title",R="primitiv-modal-description",A="primitiv-modal-close";function p(n,t){return n.childElementCount===1?n.firstElementChild:(h(n,`<${n.localName}> needs exactly one element child (${t}) to decorate.`),null)}function K(n){let t=n.firstElementChild;return n.childElementCount===1&&t instanceof HTMLDialogElement?t:(h(n,`<${v}> needs exactly one <dialog> child to decorate.`),null)}var f=class extends L{#e=null;#t=null;#n=[];#i=[];#o=null;controller={connect:()=>this.#a(),disconnect:()=>this.#c()};reconcileOn=["open"];get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",t)}#s(){return{state:()=>({open:this.open}),change:t=>this.#l(t)}}#l(t){t!==this.open&&(this.announce("primitiv-modal-change",{open:t})?this.open=t:this.#t?.sync())}#a(){this.#o=new AbortController,this.addEventListener("click",t=>this.#d(t),{signal:this.#o.signal}),this.#t?.connect()}#c(){this.#o.abort(),this.#o=null,this.#t?.disconnect(),this.#e&&i(this.#e,"open",null)}#d(t){let e=t.target;this.#n.some(o=>o.contains(e))?this.#l(!0):this.#i.some(o=>o.contains(e))&&this.#l(!1)}#u(t){t!==this.#e&&(this.#t?.disconnect(),t&&i(t,"open",null),this.#e=t,this.#t=t?new d(t,this.#s()):null,this.#t?.connect())}reconcile(){let t=this.open,e=t?"open":"closed",o=this.rootId();i(this,"data-state",e);let[r]=this.parts(v),s=r?K(r):null,[T]=this.parts(D),a=T?p(T,"a heading"):null,[x]=this.parts(R),c=x?p(x,"a <p>"):null;a&&!a.id&&(a.id=`${o}-title`),c&&!c.id&&(c.id=`${o}-description`),s&&(s.id||(s.id=`${o}-content`),i(s,"data-state",e),i(s,"aria-labelledby",a?a.id:null),i(s,"aria-describedby",c?c.id:null)),this.#n=this.#r(w);for(let u of this.#n)i(u,"aria-haspopup","dialog"),i(u,"aria-expanded",String(t)),i(u,"aria-controls",s?s.id:null);this.#i=this.#r(A),this.#u(s),this.#t?.sync()}#r(t){return this.parts(t).flatMap(e=>p(e,"a <button>")??[])}},m=class extends l{},b=class extends l{},E=class extends l{},g=class extends l{},y=class extends l{};function S(n=globalThis.customElements){M(n,[[k,f],[w,m],[v,b],[D,E],[R,g],[A,y]])}S();
@@ -0,0 +1 @@
1
+ import{a as M}from"./chunks/chunk-PKW6AKXD.js";import{a as r,b as n,c as x,d as L,f as H}from"./chunks/chunk-QVNDDONZ.js";function C(o){return o==="Escape"?{open:!1}:null}function w({open:o,nativeLightDismiss:e,inTrigger:t,inPopover:i}){return o&&!e&&!t&&!i}var p=class{#o;#e;#t=null;#s=!1;constructor(e,t){this.#o=e,this.#e=t}connect(){if(this.#t)return;this.#t=new AbortController;let{signal:e}=this.#t;this.#o.addEventListener("toggle",t=>this.#i(t),{signal:e}),this.#o.addEventListener("keydown",t=>this.#n(t),{signal:e}),document.addEventListener("click",t=>this.#r(t),{signal:e})}disconnect(){this.#t?.abort(),this.#t=null,this.#s=!1}sync(){let{open:e}=this.#e.state();if(e&&!this.#s){this.#s=!0;let t=this.#e.source?.();t?this.#o.showPopover({source:t}):this.#o.showPopover(),(this.#o.querySelector(M)??this.#o).focus()}else if(!e&&this.#s){this.#s=!1;try{this.#o.hidePopover()}catch{}}}#i(e){e.newState==="closed"&&(this.#s=!1,this.#e.change(!1))}#n(e){e.defaultPrevented||!C(e.key)||(e.preventDefault(),this.#e.change(!1),this.#e.trigger()?.focus())}#r(e){let t=e.target;w({open:this.#e.state().open,nativeLightDismiss:"popover"in HTMLElement.prototype,inTrigger:this.#e.trigger()?.contains(t)??!1,inPopover:t.closest("[popover]")!==null})&&this.#e.change(!1)}};var D="primitiv-popover",P="primitiv-popover-trigger",O="primitiv-popover-anchor",A="primitiv-popover-content",R="primitiv-popover-title",S="primitiv-popover-description",k="primitiv-popover-close";function c(o,e){return o.childElementCount===1?o.firstElementChild:(x(o,`<${o.localName}> needs exactly one element child (${e}) to decorate.`),null)}var h=class extends H{#o=null;#e=null;#t=null;#s=null;#i=[];#n=null;controller={connect:()=>this.#a(),disconnect:()=>this.#c()};reconcileOn=["open"];get open(){return this.hasAttribute("open")}set open(e){this.toggleAttribute("open",e)}#r(){return{state:()=>({open:this.open}),change:e=>this.#l(e),trigger:()=>this.#t,source:()=>this.#s??this.#t}}#l(e){e!==this.open&&(this.announce("primitiv-popover-change",{open:e})?this.open=e:queueMicrotask(()=>this.#e?.sync()))}#a(){this.#n=new AbortController,this.addEventListener("click",e=>this.#p(e),{signal:this.#n.signal}),this.#e?.connect()}#c(){this.#n.abort(),this.#n=null,this.#e?.disconnect()}#p(e){let t=e.target;this.#t?.contains(t)?this.#l(!this.open):this.#i.some(i=>i.contains(t))&&this.#l(!1)}#h(e){e!==this.#o&&(this.#e?.disconnect(),this.#o=e,this.#e=e?new p(e,this.#r()):null,this.#e?.connect())}reconcile(){let e=this.open,t=e?"open":"closed",i=this.rootId();n(this,"data-state",t);let[s=null]=this.parts(A),[E]=this.parts(P),[b]=this.parts(O),[y]=this.parts(R),[T]=this.parts(S);this.#t=E?c(E,"a <button>"):null,this.#s=b?c(b,"the element to anchor to"):null;let l=y?c(y,"a heading"):null,a=T?c(T,"a <p>"):null;l&&!l.id&&(l.id=`${i}-title`),a&&!a.id&&(a.id=`${i}-description`),s&&(s.id||(s.id=`${i}-content`),n(s,"role","dialog"),s.hasAttribute("popover")||s.setAttribute("popover","auto"),n(s,"tabindex","-1"),n(s,"data-state",t),n(s,"aria-labelledby",l?l.id:null),n(s,"aria-describedby",a?a.id:null)),this.#t&&(n(this.#t,"aria-haspopup","dialog"),n(this.#t,"aria-expanded",String(e)),n(this.#t,"aria-controls",s?s.id:null)),this.#i=this.parts(k).flatMap(N=>c(N,"a <button>")??[]),this.#h(s),this.#e?.sync()}},d=class extends r{},u=class extends r{},v=class extends r{},g=class extends r{},f=class extends r{},m=class extends r{};function I(o=globalThis.customElements){L(o,[[D,h],[P,d],[O,u],[A,v],[R,g],[S,f],[k,m]])}I();
@@ -886,6 +886,385 @@
886
886
  }
887
887
  ]
888
888
  },
889
+ {
890
+ "kind": "javascript-module",
891
+ "path": "src/popover/elements.ts",
892
+ "declarations": [
893
+ {
894
+ "kind": "class",
895
+ "description": "`<primitiv-popover>` — the state owner of a non-modal popover: a trigger\nthat opens a floating panel, built on the native Popover API. The browser\nputs the panel in the top layer and light-dismisses it; the element adds the\nrest of the WAI-ARIA non-modal dialog pattern — focus moves into the panel\nas it opens, Escape closes it and hands focus back to the trigger, and the\ntrigger's `aria-expanded` follows it.\n\nThe panel is shown with its trigger (or the anchor) as its source, which\nmakes that element the panel's implicit anchor, so CSS anchor positioning\n(`position-area`) places it with no `anchor-name` to wire.\n\nThe root finds its own parts, so a popover nested in a panel keeps its own,\nand reconciles their ARIA from its reflected state whenever a part arrives,\nleaves, or changes an attribute the root reads (the lifecycle is\n`PrimitivRootElement`'s).",
896
+ "name": "PrimitivPopoverElement",
897
+ "members": [
898
+ {
899
+ "kind": "field",
900
+ "name": "#content",
901
+ "privacy": "private",
902
+ "type": {
903
+ "text": "HTMLElement | null"
904
+ },
905
+ "default": "null",
906
+ "description": "The panel the root currently decorates, and the controller over it."
907
+ },
908
+ {
909
+ "kind": "field",
910
+ "name": "#popover",
911
+ "privacy": "private",
912
+ "type": {
913
+ "text": "PopoverController | null"
914
+ },
915
+ "default": "null"
916
+ },
917
+ {
918
+ "kind": "field",
919
+ "name": "#trigger",
920
+ "privacy": "private",
921
+ "type": {
922
+ "text": "HTMLElement | null"
923
+ },
924
+ "default": "null",
925
+ "description": "The decorated trigger and close buttons, and the anchor, as of the last reconcile."
926
+ },
927
+ {
928
+ "kind": "field",
929
+ "name": "#anchor",
930
+ "privacy": "private",
931
+ "type": {
932
+ "text": "HTMLElement | null"
933
+ },
934
+ "default": "null"
935
+ },
936
+ {
937
+ "kind": "field",
938
+ "name": "#closers",
939
+ "privacy": "private",
940
+ "type": {
941
+ "text": "HTMLElement[]"
942
+ },
943
+ "default": "[]"
944
+ },
945
+ {
946
+ "kind": "field",
947
+ "name": "#listening",
948
+ "privacy": "private",
949
+ "type": {
950
+ "text": "AbortController | null"
951
+ },
952
+ "default": "null",
953
+ "description": "The root's own click listener, while connected."
954
+ },
955
+ {
956
+ "kind": "field",
957
+ "name": "controller",
958
+ "type": {
959
+ "text": "{ connect(): void; disconnect(): void }"
960
+ },
961
+ "privacy": "protected",
962
+ "readonly": true,
963
+ "default": "{ connect: (): void => this.#connect(), disconnect: (): void => this.#disconnect(), }"
964
+ },
965
+ {
966
+ "kind": "field",
967
+ "name": "reconcileOn",
968
+ "type": {
969
+ "text": "readonly string[]"
970
+ },
971
+ "privacy": "protected",
972
+ "readonly": true,
973
+ "default": "[\"open\"]"
974
+ },
975
+ {
976
+ "kind": "field",
977
+ "name": "open",
978
+ "type": {
979
+ "text": "boolean"
980
+ },
981
+ "description": "Whether the panel is open, reflected as the boolean `open` attribute."
982
+ },
983
+ {
984
+ "kind": "method",
985
+ "name": "#host",
986
+ "privacy": "private",
987
+ "return": {
988
+ "type": {
989
+ "text": "PopoverControllerHost"
990
+ }
991
+ },
992
+ "description": "The controller's view of this element: state lives in the reflected attribute."
993
+ },
994
+ {
995
+ "kind": "method",
996
+ "name": "#change",
997
+ "privacy": "private",
998
+ "return": {
999
+ "type": {
1000
+ "text": "void"
1001
+ }
1002
+ },
1003
+ "parameters": [
1004
+ {
1005
+ "name": "open",
1006
+ "type": {
1007
+ "text": "boolean"
1008
+ }
1009
+ }
1010
+ ],
1011
+ "description": "A change the user asked for: announced first, so a listener can veto it."
1012
+ },
1013
+ {
1014
+ "kind": "method",
1015
+ "name": "#connect",
1016
+ "privacy": "private",
1017
+ "return": {
1018
+ "type": {
1019
+ "text": "void"
1020
+ }
1021
+ }
1022
+ },
1023
+ {
1024
+ "kind": "method",
1025
+ "name": "#disconnect",
1026
+ "privacy": "private",
1027
+ "return": {
1028
+ "type": {
1029
+ "text": "void"
1030
+ }
1031
+ }
1032
+ },
1033
+ {
1034
+ "kind": "method",
1035
+ "name": "#click",
1036
+ "privacy": "private",
1037
+ "return": {
1038
+ "type": {
1039
+ "text": "void"
1040
+ }
1041
+ },
1042
+ "parameters": [
1043
+ {
1044
+ "name": "event",
1045
+ "type": {
1046
+ "text": "MouseEvent"
1047
+ }
1048
+ }
1049
+ ]
1050
+ },
1051
+ {
1052
+ "kind": "method",
1053
+ "name": "#use",
1054
+ "privacy": "private",
1055
+ "return": {
1056
+ "type": {
1057
+ "text": "void"
1058
+ }
1059
+ },
1060
+ "parameters": [
1061
+ {
1062
+ "name": "content",
1063
+ "type": {
1064
+ "text": "HTMLElement | null"
1065
+ }
1066
+ }
1067
+ ],
1068
+ "description": "Decorate `content` from now on: the controller follows it. Only a\nreconcile calls this, and a root reconciles only while connected, so the\nnew controller listens at once."
1069
+ },
1070
+ {
1071
+ "kind": "method",
1072
+ "name": "reconcile",
1073
+ "privacy": "protected",
1074
+ "return": {
1075
+ "type": {
1076
+ "text": "void"
1077
+ }
1078
+ }
1079
+ }
1080
+ ],
1081
+ "events": [
1082
+ {
1083
+ "type": {
1084
+ "text": "CustomEvent<{ open: boolean }>"
1085
+ },
1086
+ "description": "Bubbles, cancelable, fired before a user-driven change is applied — a trigger or close click, Escape, or a light dismiss — with the open state afterwards. Call `preventDefault()` to veto it.",
1087
+ "name": "primitiv-popover-change"
1088
+ }
1089
+ ],
1090
+ "attributes": [
1091
+ {
1092
+ "type": {
1093
+ "text": "boolean"
1094
+ },
1095
+ "description": "Whether the panel is open. Reflected: it changes as the user opens and dismisses it, so a server re-render or a history snapshot sees the live state. Set it (or the `open` property) to open or close the panel from script.",
1096
+ "name": "open"
1097
+ }
1098
+ ],
1099
+ "superclass": {
1100
+ "name": "PrimitivRootElement",
1101
+ "module": "/src/internal/RootElement.ts"
1102
+ },
1103
+ "tagName": "primitiv-popover",
1104
+ "customElement": true,
1105
+ "summary": "The state owner of a non-modal popover on the native Popover API."
1106
+ },
1107
+ {
1108
+ "kind": "class",
1109
+ "description": "`<primitiv-popover-trigger>` — an interactive part. It decorates exactly one\nchild the consumer writes, a `<button>`, which toggles the panel and receives\n`aria-haspopup=\"dialog\"`, `aria-expanded` and `aria-controls`, so the\nrendered DOM matches React's (RFC 0033 D24).",
1110
+ "name": "PrimitivPopoverTriggerElement",
1111
+ "superclass": {
1112
+ "name": "ElementBase",
1113
+ "module": "/src/internal/element.ts"
1114
+ },
1115
+ "tagName": "primitiv-popover-trigger",
1116
+ "customElement": true
1117
+ },
1118
+ {
1119
+ "kind": "class",
1120
+ "description": "`<primitiv-popover-anchor>` — optional. It decorates exactly one element the\nconsumer writes, which the panel is anchored to in place of the trigger: a\nfield, say, whose trigger is an icon inside it.",
1121
+ "name": "PrimitivPopoverAnchorElement",
1122
+ "superclass": {
1123
+ "name": "ElementBase",
1124
+ "module": "/src/internal/element.ts"
1125
+ },
1126
+ "tagName": "primitiv-popover-anchor",
1127
+ "customElement": true
1128
+ },
1129
+ {
1130
+ "kind": "class",
1131
+ "description": "`<primitiv-popover-content>` — the panel. Structural: the root gives it an\nid, `role=\"dialog\"`, `popover=\"auto\"` (write it in your markup too, so the\npanel is hidden before the script loads), `tabindex=\"-1\"`, `data-state`, and\n`aria-labelledby` / `aria-describedby` pointing at the title and description.",
1132
+ "name": "PrimitivPopoverContentElement",
1133
+ "superclass": {
1134
+ "name": "ElementBase",
1135
+ "module": "/src/internal/element.ts"
1136
+ },
1137
+ "tagName": "primitiv-popover-content",
1138
+ "customElement": true
1139
+ },
1140
+ {
1141
+ "kind": "class",
1142
+ "description": "`<primitiv-popover-title>` — decorates exactly one heading the consumer\nwrites, whose id becomes the panel's `aria-labelledby`.",
1143
+ "name": "PrimitivPopoverTitleElement",
1144
+ "superclass": {
1145
+ "name": "ElementBase",
1146
+ "module": "/src/internal/element.ts"
1147
+ },
1148
+ "tagName": "primitiv-popover-title",
1149
+ "customElement": true
1150
+ },
1151
+ {
1152
+ "kind": "class",
1153
+ "description": "`<primitiv-popover-description>` — decorates exactly one element the\nconsumer writes (a `<p>`, usually), whose id becomes the panel's\n`aria-describedby`.",
1154
+ "name": "PrimitivPopoverDescriptionElement",
1155
+ "superclass": {
1156
+ "name": "ElementBase",
1157
+ "module": "/src/internal/element.ts"
1158
+ },
1159
+ "tagName": "primitiv-popover-description",
1160
+ "customElement": true
1161
+ },
1162
+ {
1163
+ "kind": "class",
1164
+ "description": "`<primitiv-popover-close>` — an interactive part. It decorates exactly one\n`<button>` the consumer writes, which closes the panel. A popover may have\nseveral.",
1165
+ "name": "PrimitivPopoverCloseElement",
1166
+ "superclass": {
1167
+ "name": "ElementBase",
1168
+ "module": "/src/internal/element.ts"
1169
+ },
1170
+ "tagName": "primitiv-popover-close",
1171
+ "customElement": true
1172
+ },
1173
+ {
1174
+ "kind": "function",
1175
+ "name": "definePopover",
1176
+ "return": {
1177
+ "type": {
1178
+ "text": "void"
1179
+ }
1180
+ },
1181
+ "parameters": [
1182
+ {
1183
+ "name": "registry",
1184
+ "default": "globalThis.customElements",
1185
+ "type": {
1186
+ "text": "ElementRegistry | undefined"
1187
+ }
1188
+ }
1189
+ ],
1190
+ "description": "Define the seven Popover elements on `registry` (the global `customElements`\nby default). Safe to call more than once, and a no-op where there is no\nregistry (a server render)."
1191
+ }
1192
+ ],
1193
+ "exports": [
1194
+ {
1195
+ "kind": "js",
1196
+ "name": "ElementRegistry",
1197
+ "declaration": {
1198
+ "name": "ElementRegistry",
1199
+ "module": "src/popover/elements.ts"
1200
+ }
1201
+ },
1202
+ {
1203
+ "kind": "js",
1204
+ "name": "PrimitivPopoverElement",
1205
+ "declaration": {
1206
+ "name": "PrimitivPopoverElement",
1207
+ "module": "src/popover/elements.ts"
1208
+ }
1209
+ },
1210
+ {
1211
+ "kind": "js",
1212
+ "name": "PrimitivPopoverTriggerElement",
1213
+ "declaration": {
1214
+ "name": "PrimitivPopoverTriggerElement",
1215
+ "module": "src/popover/elements.ts"
1216
+ }
1217
+ },
1218
+ {
1219
+ "kind": "js",
1220
+ "name": "PrimitivPopoverAnchorElement",
1221
+ "declaration": {
1222
+ "name": "PrimitivPopoverAnchorElement",
1223
+ "module": "src/popover/elements.ts"
1224
+ }
1225
+ },
1226
+ {
1227
+ "kind": "js",
1228
+ "name": "PrimitivPopoverContentElement",
1229
+ "declaration": {
1230
+ "name": "PrimitivPopoverContentElement",
1231
+ "module": "src/popover/elements.ts"
1232
+ }
1233
+ },
1234
+ {
1235
+ "kind": "js",
1236
+ "name": "PrimitivPopoverTitleElement",
1237
+ "declaration": {
1238
+ "name": "PrimitivPopoverTitleElement",
1239
+ "module": "src/popover/elements.ts"
1240
+ }
1241
+ },
1242
+ {
1243
+ "kind": "js",
1244
+ "name": "PrimitivPopoverDescriptionElement",
1245
+ "declaration": {
1246
+ "name": "PrimitivPopoverDescriptionElement",
1247
+ "module": "src/popover/elements.ts"
1248
+ }
1249
+ },
1250
+ {
1251
+ "kind": "js",
1252
+ "name": "PrimitivPopoverCloseElement",
1253
+ "declaration": {
1254
+ "name": "PrimitivPopoverCloseElement",
1255
+ "module": "src/popover/elements.ts"
1256
+ }
1257
+ },
1258
+ {
1259
+ "kind": "js",
1260
+ "name": "definePopover",
1261
+ "declaration": {
1262
+ "name": "definePopover",
1263
+ "module": "src/popover/elements.ts"
1264
+ }
1265
+ }
1266
+ ]
1267
+ },
889
1268
  {
890
1269
  "kind": "javascript-module",
891
1270
  "path": "src/tabs/elements.ts",
@@ -5,4 +5,5 @@
5
5
  import "./accordion.js";
6
6
  import "./collapsible.js";
7
7
  import "./modal.js";
8
+ import "./popover.js";
8
9
  import "./tabs.js";
@@ -5,4 +5,5 @@
5
5
  import "./accordion.js";
6
6
  import "./collapsible.js";
7
7
  import "./modal.js";
8
+ import "./popover.js";
8
9
  import "./tabs.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Side-effect entry: importing this module defines the seven Popover elements
3
+ * (`<primitiv-popover>`, `-trigger`, `-anchor`, `-content`, `-title`,
4
+ * `-description`, `-close`) on the global `customElements` registry.
5
+ *
6
+ * ```html
7
+ * <script type="module">import "@primitiv-ui/web/define/popover";</script>
8
+ * ```
9
+ */
10
+ import { definePopover } from "../popover/elements.js";
11
+ definePopover();
@@ -19,3 +19,7 @@ export type PrimitivCollapsibleChangeEvent = CustomEvent<{
19
19
  export type PrimitivModalChangeEvent = CustomEvent<{
20
20
  open: boolean;
21
21
  }>;
22
+ /** The `primitiv-popover-change` event: bubbles, cancelable, fired before the change applies, with the open state afterwards. */
23
+ export type PrimitivPopoverChangeEvent = CustomEvent<{
24
+ open: boolean;
25
+ }>;
@@ -21,13 +21,14 @@ import type { DetailedHTMLProps, HTMLAttributes } from "react";
21
21
  import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
22
22
  import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
23
23
  import type { PrimitivModalCloseElement, PrimitivModalContentElement, PrimitivModalDescriptionElement, PrimitivModalElement, PrimitivModalTitleElement, PrimitivModalTriggerElement } from "../modal/elements.js";
24
+ import type { PrimitivPopoverAnchorElement, PrimitivPopoverCloseElement, PrimitivPopoverContentElement, PrimitivPopoverDescriptionElement, PrimitivPopoverElement, PrimitivPopoverTitleElement, PrimitivPopoverTriggerElement } from "../popover/elements.js";
24
25
  import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
25
- import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
26
+ import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
26
27
  /** React's own props for an element, plus `class`, which React 19 passes to custom elements. */
27
28
  type ElementProps<E extends HTMLElement> = DetailedHTMLProps<HTMLAttributes<E>, E> & {
28
29
  class?: string;
29
30
  };
30
- export type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent, };
31
+ export type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent, };
31
32
  declare module "react" {
32
33
  namespace JSX {
33
34
  interface IntrinsicElements {
@@ -69,6 +70,18 @@ declare module "react" {
69
70
  "primitiv-modal-title": ElementProps<PrimitivModalTitleElement>;
70
71
  "primitiv-modal-description": ElementProps<PrimitivModalDescriptionElement>;
71
72
  "primitiv-modal-close": ElementProps<PrimitivModalCloseElement>;
73
+ "primitiv-popover": ElementProps<PrimitivPopoverElement> & {
74
+ open?: boolean;
75
+ "onprimitiv-popover-change"?: (event: PrimitivPopoverChangeEvent) => void;
76
+ };
77
+ "primitiv-popover-trigger": ElementProps<PrimitivPopoverTriggerElement>;
78
+ "primitiv-popover-anchor": ElementProps<PrimitivPopoverAnchorElement>;
79
+ "primitiv-popover-title": ElementProps<PrimitivPopoverTitleElement>;
80
+ "primitiv-popover-description": ElementProps<PrimitivPopoverDescriptionElement>;
81
+ "primitiv-popover-close": ElementProps<PrimitivPopoverCloseElement>;
82
+ "primitiv-popover-content": ElementProps<PrimitivPopoverContentElement> & {
83
+ popover?: "auto" | "manual" | "";
84
+ };
72
85
  "primitiv-tabs": ElementProps<PrimitivTabsElement> & {
73
86
  value?: string;
74
87
  orientation?: "horizontal" | "vertical";
@@ -20,8 +20,9 @@ import type { HTMLAttributes } from "svelte/elements";
20
20
  import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
21
21
  import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
22
22
  import type { PrimitivModalCloseElement, PrimitivModalContentElement, PrimitivModalDescriptionElement, PrimitivModalElement, PrimitivModalTitleElement, PrimitivModalTriggerElement } from "../modal/elements.js";
23
+ import type { PrimitivPopoverAnchorElement, PrimitivPopoverCloseElement, PrimitivPopoverContentElement, PrimitivPopoverDescriptionElement, PrimitivPopoverElement, PrimitivPopoverTitleElement, PrimitivPopoverTriggerElement } from "../popover/elements.js";
23
24
  import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
24
- import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
25
+ import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
25
26
  /** Svelte's own attributes and events for an element. */
26
27
  type Attributes<E extends HTMLElement> = HTMLAttributes<E>;
27
28
  declare module "svelte/elements" {
@@ -64,6 +65,16 @@ declare module "svelte/elements" {
64
65
  "primitiv-modal-title": Attributes<PrimitivModalTitleElement>;
65
66
  "primitiv-modal-description": Attributes<PrimitivModalDescriptionElement>;
66
67
  "primitiv-modal-close": Attributes<PrimitivModalCloseElement>;
68
+ "primitiv-popover": Attributes<PrimitivPopoverElement> & {
69
+ open?: boolean;
70
+ "onprimitiv-popover-change"?: (event: PrimitivPopoverChangeEvent) => void;
71
+ };
72
+ "primitiv-popover-trigger": Attributes<PrimitivPopoverTriggerElement>;
73
+ "primitiv-popover-anchor": Attributes<PrimitivPopoverAnchorElement>;
74
+ "primitiv-popover-content": Attributes<PrimitivPopoverContentElement>;
75
+ "primitiv-popover-title": Attributes<PrimitivPopoverTitleElement>;
76
+ "primitiv-popover-description": Attributes<PrimitivPopoverDescriptionElement>;
77
+ "primitiv-popover-close": Attributes<PrimitivPopoverCloseElement>;
67
78
  "primitiv-tabs": Attributes<PrimitivTabsElement> & {
68
79
  value?: string;
69
80
  orientation?: "horizontal" | "vertical";
@@ -19,7 +19,7 @@
19
19
  * JSR does not allow a published module to do.
20
20
  */
21
21
  import type { DefineComponent, EmitsOptions } from "vue";
22
- import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
22
+ import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
23
23
  /** A tag as Vue's template checker sees it: its props, and the events it emits. */
24
24
  type Tag<Props, Events extends EmitsOptions = Record<never, never>> = DefineComponent<Props, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Events>;
25
25
  declare module "vue" {
@@ -67,6 +67,17 @@ declare module "vue" {
67
67
  "primitiv-modal-title": Tag<Record<never, never>>;
68
68
  "primitiv-modal-description": Tag<Record<never, never>>;
69
69
  "primitiv-modal-close": Tag<Record<never, never>>;
70
+ "primitiv-popover": Tag<{
71
+ open?: boolean | "";
72
+ }, {
73
+ "primitiv-popover-change": (event: PrimitivPopoverChangeEvent) => void;
74
+ }>;
75
+ "primitiv-popover-trigger": Tag<Record<never, never>>;
76
+ "primitiv-popover-anchor": Tag<Record<never, never>>;
77
+ "primitiv-popover-content": Tag<Record<never, never>>;
78
+ "primitiv-popover-title": Tag<Record<never, never>>;
79
+ "primitiv-popover-description": Tag<Record<never, never>>;
80
+ "primitiv-popover-close": Tag<Record<never, never>>;
70
81
  "primitiv-tabs": Tag<{
71
82
  value?: string;
72
83
  orientation?: "horizontal" | "vertical";
package/dist/index.d.ts CHANGED
@@ -6,4 +6,5 @@
6
6
  export * from "./accordion/index.js";
7
7
  export * from "./collapsible/index.js";
8
8
  export * from "./modal/index.js";
9
+ export * from "./popover/index.js";
9
10
  export * from "./tabs/index.js";
package/dist/index.js CHANGED
@@ -6,4 +6,5 @@
6
6
  export * from "./accordion/index.js";
7
7
  export * from "./collapsible/index.js";
8
8
  export * from "./modal/index.js";
9
+ export * from "./popover/index.js";
9
10
  export * from "./tabs/index.js";