@primitiv-ui/web 0.1.54 → 0.1.56
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 +65 -3
- package/dist/cdn/chunks/chunk-PKW6AKXD.js +1 -0
- package/dist/cdn/modal.js +1 -1
- package/dist/cdn/popover.js +1 -0
- package/dist/cdn/tooltip.js +1 -0
- package/dist/custom-elements.json +840 -104
- package/dist/define/index.d.ts +2 -0
- package/dist/define/index.js +2 -0
- package/dist/define/popover.d.ts +1 -0
- package/dist/define/popover.js +11 -0
- package/dist/define/tooltip.d.ts +1 -0
- package/dist/define/tooltip.js +11 -0
- package/dist/frameworks/events.d.ts +8 -0
- package/dist/frameworks/react.d.ts +31 -2
- package/dist/frameworks/svelte.d.ts +26 -1
- package/dist/frameworks/vue.d.ts +26 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/popover/PopoverController.d.ts +55 -0
- package/dist/popover/PopoverController.js +100 -0
- package/dist/popover/elements.d.ts +98 -0
- package/dist/popover/elements.js +230 -0
- package/dist/popover/index.d.ts +2 -0
- package/dist/popover/index.js +2 -0
- package/dist/primitiv-web.js +1 -1
- package/dist/tags.d.ts +14 -0
- package/dist/tooltip/TooltipController.d.ts +66 -0
- package/dist/tooltip/TooltipController.js +115 -0
- package/dist/tooltip/TooltipGroup.d.ts +23 -0
- package/dist/tooltip/TooltipGroup.js +44 -0
- package/dist/tooltip/elements.d.ts +83 -0
- package/dist/tooltip/elements.js +222 -0
- package/dist/tooltip/index.d.ts +3 -0
- package/dist/tooltip/index.js +3 -0
- package/package.json +18 -2
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
|
|
9
|
+
> **Status: published.** Tabs, Accordion, Collapsible, Modal, Popover and Tooltip so far. See
|
|
10
10
|
> [RFC 0033](../../docs/rfcs/0033-web-components.md) for the design.
|
|
11
11
|
|
|
12
12
|
## Components
|
|
@@ -17,6 +17,8 @@ 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 |
|
|
21
|
+
| Tooltip | `primitiv-tooltip`, `-provider`, `-trigger`, `-content`, `-arrow` | `primitiv-tooltip-change` | 0.1.56 |
|
|
20
22
|
|
|
21
23
|
## Use it
|
|
22
24
|
|
|
@@ -49,9 +51,10 @@ downloads it once. `dist/primitiv-web.js` is the alternative: every element in
|
|
|
49
51
|
one file. Per-component files ship from 0.1.43.
|
|
50
52
|
|
|
51
53
|
The main entry (`@primitiv-ui/web`, `/tabs`, `/accordion`, `/collapsible`,
|
|
52
|
-
`/modal`) exports the classes and `defineTabs(registry?)` /
|
|
54
|
+
`/modal`, `/popover`, `/tooltip`) exports the classes and `defineTabs(registry?)` /
|
|
53
55
|
`defineAccordion(registry?)` / `defineCollapsible(registry?)` /
|
|
54
|
-
`defineModal(registry?)`
|
|
56
|
+
`defineModal(registry?)` / `definePopover(registry?)` / `defineTooltip(registry?)`
|
|
57
|
+
with **no side effects**.
|
|
55
58
|
|
|
56
59
|
**Render `hidden` on inactive panels yourself.** Until the module loads, CSS
|
|
57
60
|
cannot tell which panel is active, so markup that omits it shows every panel.
|
|
@@ -154,6 +157,65 @@ on a panel as it becomes active, for lazy loading.
|
|
|
154
157
|
press, a `<form method="dialog">` — so `preventDefault()` keeps a dirty form
|
|
155
158
|
open.
|
|
156
159
|
|
|
160
|
+
### Popover
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/cdn/popover.js"></script>
|
|
164
|
+
|
|
165
|
+
<primitiv-popover>
|
|
166
|
+
<primitiv-popover-trigger><button type="button">Share</button></primitiv-popover-trigger>
|
|
167
|
+
<primitiv-popover-content popover="auto">
|
|
168
|
+
<primitiv-popover-title><h2>Share this page</h2></primitiv-popover-title>
|
|
169
|
+
<primitiv-popover-description><p>Anyone with the link can view it.</p></primitiv-popover-description>
|
|
170
|
+
<primitiv-popover-close><button type="button">Done</button></primitiv-popover-close>
|
|
171
|
+
</primitiv-popover-content>
|
|
172
|
+
</primitiv-popover>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- **It is a native `popover="auto"` panel**: the browser supplies the top layer
|
|
176
|
+
and light dismiss. The element adds `role="dialog"` and the trigger's ARIA,
|
|
177
|
+
moves focus into the panel on open, and closes it on Escape with focus back on
|
|
178
|
+
the trigger. Write `popover="auto"` yourself so the panel is hidden before the
|
|
179
|
+
script loads.
|
|
180
|
+
- **No anchor wiring.** The panel is shown with its trigger as its source (or
|
|
181
|
+
the element inside `<primitiv-popover-anchor>`), which makes it the implicit
|
|
182
|
+
anchor, so CSS anchor positioning (`position-area`) places it with no
|
|
183
|
+
`anchor-name` / `position-anchor` pair.
|
|
184
|
+
- **`open` on the root is the state**; the `open` property reads and sets it.
|
|
185
|
+
**Listen with `primitiv-popover-change`** (bubbles, cancelable, `detail: {
|
|
186
|
+
open }`), fired before every user-driven change, a light dismiss included.
|
|
187
|
+
|
|
188
|
+
### Tooltip
|
|
189
|
+
|
|
190
|
+
```html
|
|
191
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/cdn/tooltip.js"></script>
|
|
192
|
+
|
|
193
|
+
<primitiv-tooltip>
|
|
194
|
+
<primitiv-tooltip-trigger><button type="button">Save</button></primitiv-tooltip-trigger>
|
|
195
|
+
<primitiv-tooltip-content popover="manual">
|
|
196
|
+
Saves your work
|
|
197
|
+
<primitiv-tooltip-arrow></primitiv-tooltip-arrow>
|
|
198
|
+
</primitiv-tooltip-content>
|
|
199
|
+
</primitiv-tooltip>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- **It opens on hover after `delay-duration` (700 ms) and on focus at once**,
|
|
203
|
+
and closes when the pointer leaves (after a short grace period, so the pointer
|
|
204
|
+
can reach the bubble — `disable-hoverable-content` turns that off), on blur,
|
|
205
|
+
on Escape and on a press outside. The element gives the bubble
|
|
206
|
+
`role="tooltip"` and the trigger's button `aria-describedby`.
|
|
207
|
+
- **It is a native `popover="manual"`** in the top layer, shown with the
|
|
208
|
+
trigger as its source, so CSS anchor positioning places it with no
|
|
209
|
+
`anchor-name` / `position-anchor` pair. Write `popover="manual"` yourself so
|
|
210
|
+
the bubble is hidden before the script loads.
|
|
211
|
+
- **Moving from one trigger to the next opens each next tooltip at once** (the
|
|
212
|
+
skip delay, 300 ms). Tooltips inside a `<primitiv-tooltip-provider>` share its
|
|
213
|
+
`delay-duration` and `skip-delay-duration`; the rest share a document-wide
|
|
214
|
+
window.
|
|
215
|
+
- **`open` on the root is the state**; the `open` property reads and sets it.
|
|
216
|
+
**Listen with `primitiv-tooltip-change`** (bubbles, cancelable, `detail: {
|
|
217
|
+
open }`), fired before every user-driven change.
|
|
218
|
+
|
|
157
219
|
**TypeScript** — opt into the tag map so DOM queries return the element classes:
|
|
158
220
|
`import type {} from "@primitiv-ui/web/tags"` (npm only).
|
|
159
221
|
|
|
@@ -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
|
|
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();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as l,b as s,c as f,d as E,f as T}from"./chunks/chunk-QVNDDONZ.js";function b({groupOpen:n,delay:t}){return n?0:t}var d=class{#t;#o=null;#e=null;#n=t=>this.#r(t);#i=t=>this.#p(t);constructor(t){this.#t=t}openNow(){this.#l(),this.#t.change(!0),this.#t.tooltipGroup().opened()}hoverStart(){let t=b({groupOpen:this.#t.tooltipGroup().isOpen(),delay:this.#t.delay()});if(t===0){this.openNow();return}this.#o=setTimeout(()=>{this.openNow(),this.#o=null},t)}closeNow(){this.holdOpen(),this.#t.change(!1),this.#t.tooltipGroup().closed()}hoverEnd(){this.#l(),this.#e=setTimeout(()=>{this.#t.change(!1),this.#t.tooltipGroup().closed(),this.#e=null},100)}holdOpen(){this.#e!==null&&(clearTimeout(this.#e),this.#e=null)}sync(){let{open:t}=this.#t.state();t?(document.addEventListener("keydown",this.#n),document.addEventListener("pointerdown",this.#i)):this.#s()}#s(){document.removeEventListener("keydown",this.#n),document.removeEventListener("pointerdown",this.#i)}disconnect(){this.#l(),this.holdOpen(),this.#s()}#l(){this.#o!==null&&(clearTimeout(this.#o),this.#o=null)}#r(t){t.key==="Escape"&&(this.#t.escapeKeyDown?.(t),t.defaultPrevented||this.closeNow())}#p(t){this.#t.content()?.contains(t.target)||(this.#t.pointerDownOutside?.(t),t.defaultPrevented||this.closeNow())}};var r=class{#t;#o=!1;#e=null;constructor(t){this.#t=t}isOpen(){return this.#o}opened(){this.#e!==null&&(clearTimeout(this.#e),this.#e=null),this.#o=!0}closed(){clearTimeout(this.#e??void 0),this.#e=setTimeout(()=>{this.#o=!1,this.#e=null},this.#t())}dispose(){clearTimeout(this.#e??void 0)}};var G="primitiv-tooltip",L="primitiv-tooltip-provider",y="primitiv-tooltip-trigger",O="primitiv-tooltip-content",H="primitiv-tooltip-arrow",w=700,g=300;function u(n,t,e){let i=Number(n.getAttribute(t)??Number.NaN);return Number.isNaN(i)?e:i}var R=new r(()=>g),h=class extends l{#t;get group(){return this.#t??=new r(()=>u(this,"skip-delay-duration",g))}},a=class extends T{#t=null;#o=null;#e=null;#n=null;#i=new d(this.#s());controller={connect:()=>{},disconnect:()=>this.#l()};reconcileOn=["open"];get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",t)}#s(){let t=()=>this.closest(L);return{state:()=>({open:this.open}),change:e=>{e!==this.open&&this.announce("primitiv-tooltip-change",{open:e})&&(this.open=e)},delay:()=>{let e=t();return u(this,"delay-duration",e?u(e,"delay-duration",w):w)},tooltipGroup:()=>t()?.group??R,content:()=>this.#o}}#l(){this.open&&this.#s().tooltipGroup().closed(),this.#n?.abort(),this.#n=null,this.#t=null,this.#o=null,this.#e=null,this.#i.disconnect()}#r(t,e){if(t===this.#t&&e===this.#o)return;this.#n?.abort(),this.#n=new AbortController,this.#t=t,this.#o=e;let i={signal:this.#n.signal},o=this.#i;t?.addEventListener("pointerenter",()=>o.hoverStart(),i),t?.addEventListener("pointerleave",()=>this.hasAttribute("disable-hoverable-content")?o.closeNow():o.hoverEnd(),i),t?.addEventListener("focus",()=>o.openNow(),i),t?.addEventListener("blur",()=>o.closeNow(),i),e?.addEventListener("pointerenter",()=>o.holdOpen(),i),e?.addEventListener("pointerleave",()=>o.closeNow(),i)}reconcile(){let t=this.open,e=t?"open":"closed";s(this,"data-state",e);let[i]=this.parts(y),[o=null]=this.parts(O),p=i?A(i):null;o&&(o.id||(o.id=`${this.rootId()}-content`),s(o,"role","tooltip"),o.hasAttribute("popover")||o.setAttribute("popover","manual"),s(o,"data-state",e)),p&&(s(p,"aria-describedby",o?o.id:null),s(p,"data-state",e)),this.#r(p,o),this.#p(t?o:null),this.#i.sync()}#p(t){if(t===this.#e)return;if(this.#e)try{this.#e.hidePopover()}catch{}if(this.#e=t,!t)return;let e=t;this.#t?e.showPopover({source:this.#t}):e.showPopover()}};function A(n){return n.childElementCount===1?n.firstElementChild:(f(n,`<${y}> needs exactly one element child (a <button>) to decorate.`),null)}var c=class extends l{},m=class extends l{},v=class extends l{};function N(n=globalThis.customElements){E(n,[[G,a],[L,h],[y,c],[O,m],[H,v]])}N();
|