@primitiv-ui/web 0.1.46 → 0.1.47
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 +30 -5
- package/dist/cdn/accordion.js +1 -1
- package/dist/cdn/chunks/chunk-WVI5UEAW.js +1 -0
- package/dist/cdn/collapsible.js +1 -0
- package/dist/cdn/tabs.js +1 -1
- package/dist/collapsible/CollapsibleController.d.ts +32 -0
- package/dist/collapsible/CollapsibleController.js +32 -0
- package/dist/collapsible/elements.d.ts +64 -0
- package/dist/collapsible/elements.js +173 -0
- package/dist/collapsible/index.d.ts +2 -0
- package/dist/collapsible/index.js +2 -0
- package/dist/custom-elements.json +230 -0
- package/dist/define/collapsible.d.ts +1 -0
- package/dist/define/collapsible.js +11 -0
- package/dist/define/index.d.ts +1 -0
- package/dist/define/index.js +1 -0
- package/dist/frameworks/events.d.ts +4 -0
- package/dist/frameworks/react.d.ts +15 -2
- package/dist/frameworks/svelte.d.ts +14 -1
- package/dist/frameworks/vue.d.ts +15 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/primitiv-web.js +1 -1
- package/dist/tags.d.ts +5 -0
- package/package.json +10 -2
- package/dist/cdn/chunks/chunk-FKLOMAT4.js +0 -1
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 and
|
|
9
|
+
> **Status: published.** Tabs, Accordion and Collapsible so far. See
|
|
10
10
|
> [RFC 0033](../../docs/rfcs/0033-web-components.md) for the design.
|
|
11
11
|
|
|
12
12
|
## Components
|
|
@@ -15,6 +15,7 @@ React, Vue, Angular or any other framework.
|
|
|
15
15
|
|---|---|---|---|
|
|
16
16
|
| Tabs | `primitiv-tabs`, `-list`, `-trigger`, `-content` | `primitiv-tabs-change` | 0.1.42 |
|
|
17
17
|
| Accordion | `primitiv-accordion`, `-item`, `-trigger`, `-content`, `-trigger-icon` | `primitiv-accordion-change` | 0.1.44 |
|
|
18
|
+
| Collapsible | `primitiv-collapsible`, `-trigger`, `-content`, `-trigger-icon` | `primitiv-collapsible-change` | 0.1.47 |
|
|
18
19
|
|
|
19
20
|
## Use it
|
|
20
21
|
|
|
@@ -46,9 +47,9 @@ Each `dist/cdn/<component>.js` imports the code components share from
|
|
|
46
47
|
downloads it once. `dist/primitiv-web.js` is the alternative: every element in
|
|
47
48
|
one file. Per-component files ship from 0.1.43.
|
|
48
49
|
|
|
49
|
-
The main entry (`@primitiv-ui/web`, `/tabs`, `/accordion`)
|
|
50
|
-
and `defineTabs(registry?)` / `defineAccordion(registry?)`
|
|
51
|
-
effects**.
|
|
50
|
+
The main entry (`@primitiv-ui/web`, `/tabs`, `/accordion`, `/collapsible`)
|
|
51
|
+
exports the classes and `defineTabs(registry?)` / `defineAccordion(registry?)` /
|
|
52
|
+
`defineCollapsible(registry?)` with **no side effects**.
|
|
52
53
|
|
|
53
54
|
**Render `hidden` on inactive panels yourself.** Until the module loads, CSS
|
|
54
55
|
cannot tell which panel is active, so markup that omits it shows every panel.
|
|
@@ -93,6 +94,30 @@ on a panel as it becomes active, for lazy loading.
|
|
|
93
94
|
value }`, every item open afterwards) and `primitiv-accordion-show` on a panel
|
|
94
95
|
as its item opens. Render `hidden` on closed panels yourself, as for Tabs.
|
|
95
96
|
|
|
97
|
+
### Collapsible
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/cdn/collapsible.js"></script>
|
|
101
|
+
|
|
102
|
+
<primitiv-collapsible>
|
|
103
|
+
<primitiv-collapsible-trigger><button type="button">Shipping details</button></primitiv-collapsible-trigger>
|
|
104
|
+
<primitiv-collapsible-content hidden>Orders ship within two business days.</primitiv-collapsible-content>
|
|
105
|
+
</primitiv-collapsible>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- **`open` is the state**, a boolean attribute reflected as the user toggles,
|
|
109
|
+
and the `open` property reads and sets it. `disabled` on the root keeps the
|
|
110
|
+
button focusable but stops it toggling.
|
|
111
|
+
- **`collapsed-height` on the panel** shows a clamped preview while closed (the
|
|
112
|
+
read-more pattern): a bare number is pixels, anything else a CSS length. It is
|
|
113
|
+
published as `--primitiv-collapsible-collapsed-height` with
|
|
114
|
+
`data-clamped="true"`, and the panel is never hidden, since the preview is
|
|
115
|
+
real content. `force-mount` keeps a closed panel unhidden for your own
|
|
116
|
+
animation, with `aria-hidden` instead.
|
|
117
|
+
- **Listen with `primitiv-collapsible-change`** (bubbles, cancelable, `detail: {
|
|
118
|
+
open }`) and `primitiv-collapsible-show` on the panel as it opens. Render
|
|
119
|
+
`hidden` on a closed panel yourself, as for Tabs.
|
|
120
|
+
|
|
96
121
|
**TypeScript** — opt into the tag map so DOM queries return the element classes:
|
|
97
122
|
`import type {} from "@primitiv-ui/web/tags"` (npm only).
|
|
98
123
|
|
|
@@ -127,7 +152,7 @@ The elements write no `class` and no `style`. For the registry look, apply the
|
|
|
127
152
|
|
|
128
153
|
## Layers
|
|
129
154
|
|
|
130
|
-
- **Controllers** (`TabsController`, `AccordionController`) hold a component's DOM behaviour —
|
|
155
|
+
- **Controllers** (`TabsController`, `AccordionController`, `CollapsibleController`) hold a component's DOM behaviour —
|
|
131
156
|
listeners, focus, the ordered collection of parts — and attach to whatever
|
|
132
157
|
elements register with them. They never own state; their host does.
|
|
133
158
|
- **Element hosts** (`<primitiv-tabs>` …) are the public face: they keep state
|
package/dist/cdn/accordion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as b,e as C,f as O,g,
|
|
1
|
+
import{a as b,e as C,f as O,i as g,j as n,k as v,l as H,m as f,n as R,o as M}from"./chunks/chunk-WVI5UEAW.js";var m=class extends M{#t;constructor(e,s){super(e),this.#t=s}#e(e){let{expanded:s,multiple:c}=this.#t.state(),r=C({disabled:this.disabled(),expanded:s,multiple:c},e);r!==null&&this.#t.change(r)}onTriggerClick(e){this.#e(e.value)}onTriggerKeydown(e,s){let{expanded:c,multiple:r,orientation:l,dir:d}=this.#t.state(),u=this.ordered(),p=u.map(([,o])=>o.value),t=O({values:p,disabled:this.disabled(),expanded:c,multiple:r,orientation:l,dir:d},e.value,s.key);t&&(s.preventDefault(),t.toggle!==null&&this.#e(t.toggle),t.focus!==null&&u[p.indexOf(t.focus)][0].focus())}};var k="primitiv-accordion",h="primitiv-accordion-item",w="primitiv-accordion-trigger",L="primitiv-accordion-content",S="primitiv-accordion-trigger-icon";function D(i){return(i??"").split(/\s+/).filter(Boolean)}function K(i){return i.childElementCount===1?i.firstElementChild:(v(i,`<${w}> needs exactly one element child (a <button>) to decorate.`),null)}var y=class extends R{#t=new Set;#e=!1;controller=new m(this,this.#i());reconcileOn=["value","disabled","orientation","force-mount"];get value(){return D(this.getAttribute("value"))}set value(e){this.setAttribute("value",typeof e=="string"?e:e.join(" "))}#i(){return{state:()=>({expanded:this.value,multiple:this.hasAttribute("multiple"),orientation:this.#o(),dir:this.direction()}),change:e=>{this.announce("primitiv-accordion-change",{value:e})&&(this.value=e)}}}#o(){return this.getAttribute("orientation")==="horizontal"?"horizontal":"vertical"}reconcile(){let e=new Set(this.value),s=this.rootId();n(this,"data-orientation",this.#o());let c=[];for(let r of this.parts(h)){let l=r.getAttribute("value");if(l===null){v(r,`<${h}> needs a value, which pairs it with the root's value.`);continue}let d=e.has(l),u=d?"open":"closed",[p]=f(r,w,h),[t]=f(r,L,h),o=p?K(p):null;if(o){let a=p.hasAttribute("disabled");c.push({value:l,element:o,disabled:a}),o.id||(o.id=b(s,"heading",l)),n(o,"aria-expanded",String(d)),n(o,"aria-disabled",String(a)),n(o,"data-disabled",String(a)),n(o,"data-state",u)}if(t){t.id||(t.id=b(s,"panel",l));let a=t.hasAttribute("force-mount");t.hasAttribute("role")||t.setAttribute("role","region"),n(t,"aria-labelledby",o?o.id:null),n(t,"hidden",d||a?null:""),n(t,"aria-hidden",d?null:"true"),n(t,"data-state",u),this.#e&&d&&!this.#t.has(l)&&t.dispatchEvent(new CustomEvent("primitiv-accordion-show",{bubbles:!0}))}o&&n(o,"aria-controls",t?t.id:null);for(let a of f(r,S,h))n(a,"aria-hidden","true"),n(a,"data-state",u)}this.controller.setTriggers(c),this.#t=e,this.#e=!0}},x=class extends g{},A=class extends g{},T=class extends g{},E=class extends g{};function I(i=globalThis.customElements){H(i,[[k,y],[h,x],[w,A],[L,T],[S,E]])}I();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function v(t,e,r){return`${t}-${e}-${r}`}function a({orientation:t,dir:e,homeEnd:r=!1,activate:n=!1}){let o={};if(t==="horizontal"||t==="both"){let i=e==="rtl"?"ArrowLeft":"ArrowRight",l=e==="rtl"?"ArrowRight":"ArrowLeft";o[i]="next",o[l]="prev"}return(t==="vertical"||t==="both")&&(o.ArrowDown="next",o.ArrowUp="prev"),r&&(o.Home="first",o.End="last"),n&&(o.Enter="activate",o[" "]="activate"),o}function s({action:t,navigable:e,currentKey:r}){let n=e.length;if(n===0)return null;switch(t){case"activate":return{target:r};case"first":return{target:e[0]};case"last":return{target:e[n-1]};case void 0:return null;case"next":case"prev":{let o=e.indexOf(r);if(o===-1)return null;let i=t==="next"?1:n-1;return{target:e[(o+i)%n]}}}}function f(t){return t.active??t.values[0]}function c(t,e){return t.disabled.has(e)||t.active===e?null:e}function m(t,e,r){let n=a({orientation:t.orientation,dir:t.dir,homeEnd:!0,activate:!0})[r],o=s({action:n,navigable:t.values,currentKey:e});if(!o)return null;let i=o.target,l=t.activationMode==="automatic"||n==="activate";return{focus:i,activate:l?c(t,i):null}}function T(t,e){return t.disabled.has(e)?null:t.expanded.includes(e)?t.expanded.filter(r=>r!==e):t.multiple?[...t.expanded,e]:[e]}function h(t,e,r){let n=a({orientation:t.orientation,dir:t.dir,homeEnd:!0,activate:!0})[r];if(n==="activate")return t.disabled.has(e)?null:{focus:null,toggle:e};let o=t.values.filter(l=>!t.disabled.has(l)),i=s({action:n,navigable:o,currentKey:e});return i&&{focus:i.target,toggle:null}}function d(t){return t.disabled?null:!t.open}function x(t,e){if(e!=="Enter"&&e!==" ")return null;let r=d(t);return r===null?null:{open:r}}var u=globalThis.HTMLElement??class{};function $(t,e,r){t.getAttribute(e)!==r&&(r===null?t.removeAttribute(e):t.setAttribute(e,r))}var g=new WeakSet;function z(t,e){g.has(t)||(g.add(t),console.error(e,t))}function G(t,e){if(t)for(let[r,n]of e)t.get(r)||t.define(r,n)}function p(t,e,r){return[...t.querySelectorAll(e)].filter(n=>n.closest(r)===t)}var A=0,b=class extends u{#t;#e=new MutationObserver(()=>this.reconcile());connectedCallback(){this.controller.connect(),this.#e.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:[...this.reconcileOn]}),this.reconcile()}disconnectedCallback(){this.controller.disconnect(),this.#e.disconnect()}rootId(){return this.id||(this.#t??=`${this.localName}-${++A}`)}direction(){return this.matches(":dir(rtl)")?"rtl":"ltr"}parts(e){return p(this,e,this.localName)}announce(e,r){return this.dispatchEvent(new CustomEvent(e,{bubbles:!0,cancelable:!0,detail:r}))}};var y=class{#t;#e=new Map;#r=null;constructor(e){this.#t=e}registerTrigger(e,r,n={}){this.#e.set(r,{value:e,disabled:n.disabled??!1})}setTriggers(e){this.#e.clear();for(let{value:r,element:n,disabled:o}of e)this.registerTrigger(r,n,{disabled:o})}unregisterTrigger(e){this.#e.delete(e)}connect(){if(this.#r)return;this.#r=new AbortController;let{signal:e}=this.#r;this.#t.addEventListener("click",r=>this.#n(r,this.onTriggerClick),{signal:e}),this.#t.addEventListener("keydown",r=>this.#n(r,this.onTriggerKeydown),{signal:e})}disconnect(){this.#r?.abort(),this.#r=null}ordered(){return[...this.#e].sort(([e],[r])=>e.compareDocumentPosition(r)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1)}disabled(){let e=new Set;for(let r of this.#e.values())r.disabled&&e.add(r.value);return e}#n(e,r){for(let[n,o]of this.#e)if(n.contains(e.target))return r.call(this,o,e)}};export{v as a,f as b,c,m as d,T as e,h as f,d as g,x as h,u as i,$ as j,z as k,G as l,p as m,b as n,y as o};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as y,h as T,i as d,j as i,k as x,l as C,n as E,o as v}from"./chunks/chunk-WVI5UEAW.js";var p=class extends v{#t;constructor(t,o){super(t),this.#t=o}onTriggerClick(t){let o=y({open:this.#t.state().open,disabled:t.disabled});o!==null&&this.#t.change(o)}onTriggerKeydown(t,o){let s=T({open:this.#t.state().open,disabled:t.disabled},o.key);s&&(o.preventDefault(),this.#t.change(s.open))}};var R="primitiv-collapsible",b="primitiv-collapsible-trigger",H="primitiv-collapsible-content",w="primitiv-collapsible-trigger-icon",L="--primitiv-collapsible-collapsed-height";function O(e){return e.childElementCount===1?e.firstElementChild:(x(e,`<${b}> needs exactly one element child (a <button>) to decorate.`),null)}function M(e){return Number.isNaN(Number(e))?e:`${e}px`}function I(e,t,o){e.style.getPropertyValue(t)!==o&&(e.style.setProperty(t,o),e.getAttribute("style")===""&&e.removeAttribute("style"))}var c=class extends E{#t;controller=new p(this,this.#e());reconcileOn=["open","disabled","force-mount","collapsed-height"];get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",t)}#e(){return{state:()=>({open:this.open}),change:t=>{this.announce("primitiv-collapsible-change",{open:t})&&(this.open=t)}}}reconcile(){let t=this.open,o=t?"open":"closed",s=this.hasAttribute("disabled"),m=this.rootId();i(this,"data-state",o),i(this,"data-disabled",String(s));let[f]=this.parts(b),[n]=this.parts(H),r=f?O(f):null;if(r&&(r.id||(r.id=`${m}-trigger`),i(r,"aria-expanded",String(t)),i(r,"aria-disabled",s?"true":null),i(r,"data-disabled",String(s)),i(r,"data-state",o)),n){n.id||(n.id=`${m}-content`);let l=n.getAttribute("collapsed-height"),a=l!==null,N=a||n.hasAttribute("force-mount");i(n,"hidden",t||N?null:""),i(n,"aria-hidden",t||a?null:"true"),i(n,"data-state",o),i(n,"data-disabled",String(s)),i(n,"data-clamped",a?"true":null),I(n,L,a?M(l):""),t&&this.#t===!1&&n.dispatchEvent(new CustomEvent("primitiv-collapsible-show",{bubbles:!0}))}r&&i(r,"aria-controls",n?n.id:null);for(let l of this.parts(w))i(l,"aria-hidden","true"),i(l,"data-state",o);this.controller.setTriggers(r?[{value:"trigger",element:r,disabled:s}]:[]),this.#t=t}},h=class extends d{},u=class extends d{},g=class extends d{};function A(e=globalThis.customElements){C(e,[[R,c],[b,h],[H,u],[w,g]])}A();
|
package/dist/cdn/tabs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as h,b as M,c as A,d as C,
|
|
1
|
+
import{a as h,b as M,c as A,d as C,i as b,j as a,k as O,l as H,n as w,o as R}from"./chunks/chunk-WVI5UEAW.js";var v=class extends R{#t;constructor(i,n){super(i),this.#t=n}onTriggerClick(i){let{active:n}=this.#t.state(),r=A({disabled:this.disabled(),active:n},i.value);if(r!==null){let l=this.ordered().map(([,d])=>d.value);this.#t.activate(r,l.indexOf(r))}}onTriggerKeydown(i,n){let{active:r,orientation:l,dir:d,activationMode:p}=this.#t.state(),u=this.ordered(),e=u.map(([,o])=>o.value),t=C({values:e,disabled:this.disabled(),active:r,orientation:l,dir:d,activationMode:p},i.value,n.key);t&&(n.preventDefault(),t.activate!==null&&this.#t.activate(t.activate,e.indexOf(t.activate)),u[e.indexOf(t.focus)][0].focus())}};var D="primitiv-tabs",I="primitiv-tabs-list",y="primitiv-tabs-trigger",L="primitiv-tabs-content";function K(s){let i=s.getAttribute("value");return s.childElementCount===1&&i!==null?{tab:s.firstElementChild,value:i}:(O(s,`<${y}> needs a value and exactly one element child (a <button>, an <a href> or a router link) to decorate.`),null)}var f=class extends w{#t;#e=!1;controller=new v(this,this.#a());reconcileOn=["value","disabled","label","orientation"];get value(){return this.getAttribute("value")??void 0}set value(i){this.setAttribute("value",i)}#a(){return{state:()=>({active:this.value,orientation:this.#i(),dir:this.direction(),activationMode:this.#n()}),activate:(i,n)=>{this.announce("primitiv-tabs-change",{value:i,index:n})&&(this.value=i)}}}#n(){let i=this.getAttribute("activation-mode");return i==="manual"?i:"automatic"}#i(){return this.getAttribute("orientation")==="vertical"?"vertical":"horizontal"}reconcile(){let i=this.#i(),n=this.value,r=this.rootId();a(this,"data-orientation",i);for(let e of this.parts(I)){a(e,"role","tablist"),a(e,"aria-orientation",i),a(e,"data-orientation",i);let t=e.getAttribute("label");t!==null&&a(e,"aria-label",t)}let l=new Map;for(let e of this.parts(L)){let t=e.getAttribute("value");t!==null&&l.set(t,e)}let d=this.parts(y).flatMap(e=>{let t=K(e);return t?[{trigger:e,...t}]:[]}),p=M({values:d.map(e=>e.value),active:n});this.controller.setTriggers(d.map(({trigger:e,tab:t,value:o})=>({value:o,element:t,disabled:e.hasAttribute("disabled")})));for(let{trigger:e,tab:t,value:o}of d){let c=l.get(o),x=o===n,E=e.hasAttribute("disabled");t.id||(t.id=h(r,"trigger",o)),c&&!c.id&&(c.id=h(r,"panel",o)),a(t,"role","tab"),a(t,"aria-selected",String(x)),a(t,"aria-controls",c?c.id:null),a(t,"tabindex",o===p?"0":"-1"),a(t,"aria-disabled",E?"true":null),a(t,"data-disabled",E?"":null),a(t,"data-state",x?"active":"inactive"),a(t,"data-orientation",i),c&&a(c,"aria-labelledby",t.id)}for(let[e,t]of l){let o=e===n;a(t,"role","tabpanel"),a(t,"tabindex","0"),a(t,"hidden",o?null:""),a(t,"data-state",o?"active":"inactive"),a(t,"data-orientation",i)}let u=l.get(n);this.#e&&n!==this.#t&&u&&u.dispatchEvent(new CustomEvent("primitiv-tabs-show",{bubbles:!0})),this.#t=n,this.#e=!0}},m=class extends b{},g=class extends b{},T=class extends b{};function k(s=globalThis.customElements){H(s,[[D,f],[I,m],[y,g],[L,T]])}k();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TriggerController, type Trigger } from "../internal/TriggerController.js";
|
|
2
|
+
/**
|
|
3
|
+
* What a {@link CollapsibleController} asks of whoever hosts it. The controller
|
|
4
|
+
* owns behaviour and never owns state (RFC 0033 D28): the custom elements keep
|
|
5
|
+
* the open state in a reflected `open` attribute, the React adapter keeps it in
|
|
6
|
+
* React, and each answers these two calls from wherever it keeps it.
|
|
7
|
+
*/
|
|
8
|
+
export type CollapsibleControllerHost = {
|
|
9
|
+
/** The state the controller cannot see for itself. */
|
|
10
|
+
state(): {
|
|
11
|
+
/** Whether the panel is open. */
|
|
12
|
+
open: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** Apply a change the user asked for: `open` is the state afterwards. */
|
|
15
|
+
change(open: boolean): void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The DOM behaviour of a collapsible: a click, Enter or Space on its trigger
|
|
19
|
+
* toggles it. It attaches to whatever trigger registers with it, so the same
|
|
20
|
+
* code runs under the custom elements and under the React adapter, which renders
|
|
21
|
+
* its own markup (RFC 0033 §3.4). There is one trigger; registering it
|
|
22
|
+
* `disabled` disables the collapsible — it stays focusable and never toggles.
|
|
23
|
+
* Enter and Space are handled here, not left to native activation, so a
|
|
24
|
+
* trigger that is not a `<button>` (an `<a>`, a `<div role="button">`)
|
|
25
|
+
* toggles too.
|
|
26
|
+
*/
|
|
27
|
+
export declare class CollapsibleController extends TriggerController {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(root: HTMLElement, host: CollapsibleControllerHost);
|
|
30
|
+
protected onTriggerClick(trigger: Trigger): void;
|
|
31
|
+
protected onTriggerKeydown(trigger: Trigger, event: KeyboardEvent): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { collapsibleKeydown, collapsibleToggle } from "@primitiv-ui/core";
|
|
2
|
+
import { TriggerController } from "../internal/TriggerController.js";
|
|
3
|
+
/**
|
|
4
|
+
* The DOM behaviour of a collapsible: a click, Enter or Space on its trigger
|
|
5
|
+
* toggles it. It attaches to whatever trigger registers with it, so the same
|
|
6
|
+
* code runs under the custom elements and under the React adapter, which renders
|
|
7
|
+
* its own markup (RFC 0033 §3.4). There is one trigger; registering it
|
|
8
|
+
* `disabled` disables the collapsible — it stays focusable and never toggles.
|
|
9
|
+
* Enter and Space are handled here, not left to native activation, so a
|
|
10
|
+
* trigger that is not a `<button>` (an `<a>`, a `<div role="button">`)
|
|
11
|
+
* toggles too.
|
|
12
|
+
*/
|
|
13
|
+
export class CollapsibleController extends TriggerController {
|
|
14
|
+
#host;
|
|
15
|
+
constructor(root, host) {
|
|
16
|
+
super(root);
|
|
17
|
+
this.#host = host;
|
|
18
|
+
}
|
|
19
|
+
onTriggerClick(trigger) {
|
|
20
|
+
const open = collapsibleToggle({ open: this.#host.state().open, disabled: trigger.disabled });
|
|
21
|
+
if (open !== null)
|
|
22
|
+
this.#host.change(open);
|
|
23
|
+
}
|
|
24
|
+
onTriggerKeydown(trigger, event) {
|
|
25
|
+
const outcome = collapsibleKeydown({ open: this.#host.state().open, disabled: trigger.disabled }, event.key);
|
|
26
|
+
if (!outcome)
|
|
27
|
+
return;
|
|
28
|
+
// Enter and Space would also click a button; the toggle happens here once.
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
this.#host.change(outcome.open);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ElementBase, type ElementRegistry } from "../internal/element.js";
|
|
2
|
+
import { PrimitivRootElement } from "../internal/RootElement.js";
|
|
3
|
+
import { CollapsibleController } from "./CollapsibleController.js";
|
|
4
|
+
export type { ElementRegistry };
|
|
5
|
+
/**
|
|
6
|
+
* `<primitiv-collapsible>` — the state owner of a single disclosure: a trigger
|
|
7
|
+
* that shows and hides one panel.
|
|
8
|
+
*
|
|
9
|
+
* The root finds its own parts, so a collapsible nested in a panel keeps its
|
|
10
|
+
* own, and reconciles their ARIA from its reflected state whenever a part
|
|
11
|
+
* arrives, leaves, or changes an attribute the root reads (the lifecycle is
|
|
12
|
+
* `PrimitivRootElement`'s).
|
|
13
|
+
*
|
|
14
|
+
* @customElement primitiv-collapsible
|
|
15
|
+
* @summary The state owner of a single disclosure: a trigger that shows and hides one panel.
|
|
16
|
+
* @attr {boolean} open - Whether the panel is open. Reflected: it changes as the user toggles, so a server re-render or a history snapshot sees the live state.
|
|
17
|
+
* @attr {boolean} disabled - Disables the collapsible: the trigger's button stays focusable, is marked `aria-disabled`, and never toggles.
|
|
18
|
+
* @fires {CustomEvent<{ open: boolean }>} primitiv-collapsible-change - Bubbles, cancelable, fired before a user-driven toggle is applied, with the open state afterwards. Call `preventDefault()` to veto it.
|
|
19
|
+
*/
|
|
20
|
+
export declare class PrimitivCollapsibleElement extends PrimitivRootElement {
|
|
21
|
+
#private;
|
|
22
|
+
protected readonly controller: CollapsibleController;
|
|
23
|
+
protected readonly reconcileOn: readonly string[];
|
|
24
|
+
/** Whether the panel is open, reflected as the boolean `open` attribute. */
|
|
25
|
+
get open(): boolean;
|
|
26
|
+
set open(next: boolean);
|
|
27
|
+
protected reconcile(): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `<primitiv-collapsible-trigger>` — an interactive part. It decorates exactly
|
|
31
|
+
* one child the consumer writes, a `<button>`, which receives `aria-expanded`,
|
|
32
|
+
* `aria-controls` and the state attributes, so the rendered DOM matches React's
|
|
33
|
+
* `<button aria-expanded>` (RFC 0033 D24).
|
|
34
|
+
*
|
|
35
|
+
* @customElement primitiv-collapsible-trigger
|
|
36
|
+
*/
|
|
37
|
+
export declare class PrimitivCollapsibleTriggerElement extends ElementBase {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `<primitiv-collapsible-content>` — the panel. Structural: the root writes its
|
|
41
|
+
* id and state and hides it while closed.
|
|
42
|
+
*
|
|
43
|
+
* @customElement primitiv-collapsible-content
|
|
44
|
+
* @attr {boolean} force-mount - Never sets `hidden`, so styles can animate the panel open and closed. A closed panel always carries `aria-hidden`, so it stays out of the accessibility tree either way.
|
|
45
|
+
* @attr {string} collapsed-height - Shows a clamped preview while closed instead of hiding the panel (the read-more pattern). A bare number is pixels; anything else is a CSS length, used verbatim. Published as the `--primitiv-collapsible-collapsed-height` custom property, with `data-clamped="true"`; the panel is never hidden, since the preview is real content.
|
|
46
|
+
* @fires {CustomEvent} primitiv-collapsible-show - Bubbles from the panel as it opens (not on first render), so a lazy panel can fetch its content.
|
|
47
|
+
*/
|
|
48
|
+
export declare class PrimitivCollapsibleContentElement extends ElementBase {
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `<primitiv-collapsible-trigger-icon>` — a decorative indicator, usually inside
|
|
52
|
+
* the trigger's button. The root hides it from assistive technology and mirrors
|
|
53
|
+
* the `data-state`, for a chevron that flips.
|
|
54
|
+
*
|
|
55
|
+
* @customElement primitiv-collapsible-trigger-icon
|
|
56
|
+
*/
|
|
57
|
+
export declare class PrimitivCollapsibleTriggerIconElement extends ElementBase {
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Define the four Collapsible elements on `registry` (the global
|
|
61
|
+
* `customElements` by default). Safe to call more than once, and a no-op where
|
|
62
|
+
* there is no registry (a server render).
|
|
63
|
+
*/
|
|
64
|
+
export declare function defineCollapsible(registry?: ElementRegistry | undefined): void;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { defineElements, ElementBase, reportOnce, write } from "../internal/element.js";
|
|
2
|
+
import { PrimitivRootElement } from "../internal/RootElement.js";
|
|
3
|
+
import { CollapsibleController } from "./CollapsibleController.js";
|
|
4
|
+
// Stryker disable StringLiteral: static — evaluated once at import, so runtime mutant switching never reaches them; the names are pinned by the defineCollapsible registry test instead.
|
|
5
|
+
const ROOT = "primitiv-collapsible";
|
|
6
|
+
const TRIGGER = "primitiv-collapsible-trigger";
|
|
7
|
+
const CONTENT = "primitiv-collapsible-content";
|
|
8
|
+
const ICON = "primitiv-collapsible-trigger-icon";
|
|
9
|
+
const HEIGHT = "--primitiv-collapsible-collapsed-height";
|
|
10
|
+
// Stryker restore StringLiteral
|
|
11
|
+
/**
|
|
12
|
+
* A trigger decorates exactly one element child — the `<button>` the consumer
|
|
13
|
+
* writes. Anything else is reported once and left undecorated rather than
|
|
14
|
+
* thrown (RFC 0033 D24).
|
|
15
|
+
*/
|
|
16
|
+
function decoratable(trigger) {
|
|
17
|
+
if (trigger.childElementCount === 1)
|
|
18
|
+
return trigger.firstElementChild;
|
|
19
|
+
reportOnce(trigger, `<${TRIGGER}> needs exactly one element child (a <button>) to decorate.`);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
/** A `collapsed-height` as a CSS length: a bare number is pixels, anything else is used verbatim. */
|
|
23
|
+
function cssLength(value) {
|
|
24
|
+
return Number.isNaN(Number(value)) ? value : `${value}px`;
|
|
25
|
+
}
|
|
26
|
+
/** Set or remove (`""`) a custom property, only when it would change (D20). */
|
|
27
|
+
function writeProperty(element, name, value) {
|
|
28
|
+
if (element.style.getPropertyValue(name) === value)
|
|
29
|
+
return;
|
|
30
|
+
// Setting the empty string removes the property (CSSOM).
|
|
31
|
+
element.style.setProperty(name, value);
|
|
32
|
+
// Removing the last property leaves `style=""` behind; drop it.
|
|
33
|
+
if (element.getAttribute("style") === "")
|
|
34
|
+
element.removeAttribute("style");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `<primitiv-collapsible>` — the state owner of a single disclosure: a trigger
|
|
38
|
+
* that shows and hides one panel.
|
|
39
|
+
*
|
|
40
|
+
* The root finds its own parts, so a collapsible nested in a panel keeps its
|
|
41
|
+
* own, and reconciles their ARIA from its reflected state whenever a part
|
|
42
|
+
* arrives, leaves, or changes an attribute the root reads (the lifecycle is
|
|
43
|
+
* `PrimitivRootElement`'s).
|
|
44
|
+
*
|
|
45
|
+
* @customElement primitiv-collapsible
|
|
46
|
+
* @summary The state owner of a single disclosure: a trigger that shows and hides one panel.
|
|
47
|
+
* @attr {boolean} open - Whether the panel is open. Reflected: it changes as the user toggles, so a server re-render or a history snapshot sees the live state.
|
|
48
|
+
* @attr {boolean} disabled - Disables the collapsible: the trigger's button stays focusable, is marked `aria-disabled`, and never toggles.
|
|
49
|
+
* @fires {CustomEvent<{ open: boolean }>} primitiv-collapsible-change - Bubbles, cancelable, fired before a user-driven toggle is applied, with the open state afterwards. Call `preventDefault()` to veto it.
|
|
50
|
+
*/
|
|
51
|
+
export class PrimitivCollapsibleElement extends PrimitivRootElement {
|
|
52
|
+
/**
|
|
53
|
+
* Whether the panel was open at the last reconcile, so opening fires
|
|
54
|
+
* primitiv-collapsible-show; `undefined` until the first render.
|
|
55
|
+
*/
|
|
56
|
+
#shown;
|
|
57
|
+
controller = new CollapsibleController(this, this.#host());
|
|
58
|
+
reconcileOn = ["open", "disabled", "force-mount", "collapsed-height"];
|
|
59
|
+
/** Whether the panel is open, reflected as the boolean `open` attribute. */
|
|
60
|
+
get open() {
|
|
61
|
+
return this.hasAttribute("open");
|
|
62
|
+
}
|
|
63
|
+
set open(next) {
|
|
64
|
+
this.toggleAttribute("open", next);
|
|
65
|
+
}
|
|
66
|
+
/** The controller's view of this element: state lives in reflected attributes. */
|
|
67
|
+
#host() {
|
|
68
|
+
return {
|
|
69
|
+
state: () => ({ open: this.open }),
|
|
70
|
+
change: (open) => {
|
|
71
|
+
if (this.announce("primitiv-collapsible-change", { open }))
|
|
72
|
+
this.open = open;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
reconcile() {
|
|
77
|
+
const open = this.open;
|
|
78
|
+
const state = open ? "open" : "closed";
|
|
79
|
+
const disabled = this.hasAttribute("disabled");
|
|
80
|
+
const rootId = this.rootId();
|
|
81
|
+
write(this, "data-state", state);
|
|
82
|
+
write(this, "data-disabled", String(disabled));
|
|
83
|
+
const [trigger] = this.parts(TRIGGER);
|
|
84
|
+
const [panel] = this.parts(CONTENT);
|
|
85
|
+
const button = trigger ? decoratable(trigger) : null;
|
|
86
|
+
if (button) {
|
|
87
|
+
if (!button.id)
|
|
88
|
+
button.id = `${rootId}-trigger`;
|
|
89
|
+
write(button, "aria-expanded", String(open));
|
|
90
|
+
write(button, "aria-disabled", disabled ? "true" : null);
|
|
91
|
+
write(button, "data-disabled", String(disabled));
|
|
92
|
+
write(button, "data-state", state);
|
|
93
|
+
}
|
|
94
|
+
if (panel) {
|
|
95
|
+
if (!panel.id)
|
|
96
|
+
panel.id = `${rootId}-content`;
|
|
97
|
+
const height = panel.getAttribute("collapsed-height");
|
|
98
|
+
// A clamped preview is real, readable content while closed, so it is
|
|
99
|
+
// never hidden; a force-mount panel stays rendered so styles can animate it.
|
|
100
|
+
const clamped = height !== null;
|
|
101
|
+
const mounted = clamped || panel.hasAttribute("force-mount");
|
|
102
|
+
write(panel, "hidden", open || mounted ? null : "");
|
|
103
|
+
// Every closed panel but a preview, not only a force-mount one: a
|
|
104
|
+
// stylesheet that animates the panel gives it a display that wins over
|
|
105
|
+
// `hidden` (the registry's does), which would leave it exposed.
|
|
106
|
+
write(panel, "aria-hidden", open || clamped ? null : "true");
|
|
107
|
+
write(panel, "data-state", state);
|
|
108
|
+
write(panel, "data-disabled", String(disabled));
|
|
109
|
+
write(panel, "data-clamped", clamped ? "true" : null);
|
|
110
|
+
writeProperty(panel, HEIGHT, clamped ? cssLength(height) : "");
|
|
111
|
+
// Opening announces it, so a lazy panel can fetch its content
|
|
112
|
+
// (`hx-trigger="primitiv-collapsible-show once"`). The first render shows
|
|
113
|
+
// what the server already rendered, so it announces nothing.
|
|
114
|
+
if (open && this.#shown === false) {
|
|
115
|
+
panel.dispatchEvent(new CustomEvent("primitiv-collapsible-show", { bubbles: true }));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (button)
|
|
119
|
+
write(button, "aria-controls", panel ? panel.id : null);
|
|
120
|
+
for (const icon of this.parts(ICON)) {
|
|
121
|
+
write(icon, "aria-hidden", "true");
|
|
122
|
+
write(icon, "data-state", state);
|
|
123
|
+
}
|
|
124
|
+
// Replace the registration wholesale: a trigger whose child was re-rendered
|
|
125
|
+
// simply is not registered again.
|
|
126
|
+
// Stryker disable next-line StringLiteral: equivalent — a collapsible has one trigger, so its value is never read.
|
|
127
|
+
this.controller.setTriggers(button ? [{ value: "trigger", element: button, disabled }] : []);
|
|
128
|
+
this.#shown = open;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* `<primitiv-collapsible-trigger>` — an interactive part. It decorates exactly
|
|
133
|
+
* one child the consumer writes, a `<button>`, which receives `aria-expanded`,
|
|
134
|
+
* `aria-controls` and the state attributes, so the rendered DOM matches React's
|
|
135
|
+
* `<button aria-expanded>` (RFC 0033 D24).
|
|
136
|
+
*
|
|
137
|
+
* @customElement primitiv-collapsible-trigger
|
|
138
|
+
*/
|
|
139
|
+
export class PrimitivCollapsibleTriggerElement extends ElementBase {
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* `<primitiv-collapsible-content>` — the panel. Structural: the root writes its
|
|
143
|
+
* id and state and hides it while closed.
|
|
144
|
+
*
|
|
145
|
+
* @customElement primitiv-collapsible-content
|
|
146
|
+
* @attr {boolean} force-mount - Never sets `hidden`, so styles can animate the panel open and closed. A closed panel always carries `aria-hidden`, so it stays out of the accessibility tree either way.
|
|
147
|
+
* @attr {string} collapsed-height - Shows a clamped preview while closed instead of hiding the panel (the read-more pattern). A bare number is pixels; anything else is a CSS length, used verbatim. Published as the `--primitiv-collapsible-collapsed-height` custom property, with `data-clamped="true"`; the panel is never hidden, since the preview is real content.
|
|
148
|
+
* @fires {CustomEvent} primitiv-collapsible-show - Bubbles from the panel as it opens (not on first render), so a lazy panel can fetch its content.
|
|
149
|
+
*/
|
|
150
|
+
export class PrimitivCollapsibleContentElement extends ElementBase {
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* `<primitiv-collapsible-trigger-icon>` — a decorative indicator, usually inside
|
|
154
|
+
* the trigger's button. The root hides it from assistive technology and mirrors
|
|
155
|
+
* the `data-state`, for a chevron that flips.
|
|
156
|
+
*
|
|
157
|
+
* @customElement primitiv-collapsible-trigger-icon
|
|
158
|
+
*/
|
|
159
|
+
export class PrimitivCollapsibleTriggerIconElement extends ElementBase {
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Define the four Collapsible elements on `registry` (the global
|
|
163
|
+
* `customElements` by default). Safe to call more than once, and a no-op where
|
|
164
|
+
* there is no registry (a server render).
|
|
165
|
+
*/
|
|
166
|
+
export function defineCollapsible(registry = globalThis.customElements) {
|
|
167
|
+
defineElements(registry, [
|
|
168
|
+
[ROOT, PrimitivCollapsibleElement],
|
|
169
|
+
[TRIGGER, PrimitivCollapsibleTriggerElement],
|
|
170
|
+
[CONTENT, PrimitivCollapsibleContentElement],
|
|
171
|
+
[ICON, PrimitivCollapsibleTriggerIconElement],
|
|
172
|
+
]);
|
|
173
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { CollapsibleController, type CollapsibleControllerHost } from "./CollapsibleController.js";
|
|
2
|
+
export { defineCollapsible, PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement, } from "./elements.js";
|
|
@@ -286,6 +286,236 @@
|
|
|
286
286
|
}
|
|
287
287
|
]
|
|
288
288
|
},
|
|
289
|
+
{
|
|
290
|
+
"kind": "javascript-module",
|
|
291
|
+
"path": "src/collapsible/elements.ts",
|
|
292
|
+
"declarations": [
|
|
293
|
+
{
|
|
294
|
+
"kind": "class",
|
|
295
|
+
"description": "`<primitiv-collapsible>` — the state owner of a single disclosure: a trigger\nthat shows and hides one panel.\n\nThe root finds its own parts, so a collapsible nested in a panel keeps its\nown, and reconciles their ARIA from its reflected state whenever a part\narrives, leaves, or changes an attribute the root reads (the lifecycle is\n`PrimitivRootElement`'s).",
|
|
296
|
+
"name": "PrimitivCollapsibleElement",
|
|
297
|
+
"members": [
|
|
298
|
+
{
|
|
299
|
+
"kind": "field",
|
|
300
|
+
"name": "#shown",
|
|
301
|
+
"privacy": "private",
|
|
302
|
+
"type": {
|
|
303
|
+
"text": "boolean | undefined"
|
|
304
|
+
},
|
|
305
|
+
"description": "Whether the panel was open at the last reconcile, so opening fires\nprimitiv-collapsible-show; `undefined` until the first render."
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"kind": "field",
|
|
309
|
+
"name": "controller",
|
|
310
|
+
"type": {
|
|
311
|
+
"text": "CollapsibleController"
|
|
312
|
+
},
|
|
313
|
+
"privacy": "protected",
|
|
314
|
+
"readonly": true,
|
|
315
|
+
"default": "new CollapsibleController(this, this.#host())"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"kind": "field",
|
|
319
|
+
"name": "reconcileOn",
|
|
320
|
+
"type": {
|
|
321
|
+
"text": "readonly string[]"
|
|
322
|
+
},
|
|
323
|
+
"privacy": "protected",
|
|
324
|
+
"readonly": true,
|
|
325
|
+
"default": "[\"open\", \"disabled\", \"force-mount\", \"collapsed-height\"]"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"kind": "field",
|
|
329
|
+
"name": "open",
|
|
330
|
+
"type": {
|
|
331
|
+
"text": "boolean"
|
|
332
|
+
},
|
|
333
|
+
"description": "Whether the panel is open, reflected as the boolean `open` attribute."
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"kind": "method",
|
|
337
|
+
"name": "#host",
|
|
338
|
+
"privacy": "private",
|
|
339
|
+
"return": {
|
|
340
|
+
"type": {
|
|
341
|
+
"text": "CollapsibleControllerHost"
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"description": "The controller's view of this element: state lives in reflected attributes."
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"kind": "method",
|
|
348
|
+
"name": "reconcile",
|
|
349
|
+
"privacy": "protected",
|
|
350
|
+
"return": {
|
|
351
|
+
"type": {
|
|
352
|
+
"text": "void"
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
],
|
|
357
|
+
"events": [
|
|
358
|
+
{
|
|
359
|
+
"type": {
|
|
360
|
+
"text": "CustomEvent<{ open: boolean }>"
|
|
361
|
+
},
|
|
362
|
+
"description": "Bubbles, cancelable, fired before a user-driven toggle is applied, with the open state afterwards. Call `preventDefault()` to veto it.",
|
|
363
|
+
"name": "primitiv-collapsible-change"
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
"attributes": [
|
|
367
|
+
{
|
|
368
|
+
"type": {
|
|
369
|
+
"text": "boolean"
|
|
370
|
+
},
|
|
371
|
+
"description": "Whether the panel is open. Reflected: it changes as the user toggles, so a server re-render or a history snapshot sees the live state.",
|
|
372
|
+
"name": "open"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"type": {
|
|
376
|
+
"text": "boolean"
|
|
377
|
+
},
|
|
378
|
+
"description": "Disables the collapsible: the trigger's button stays focusable, is marked `aria-disabled`, and never toggles.",
|
|
379
|
+
"name": "disabled"
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
"superclass": {
|
|
383
|
+
"name": "PrimitivRootElement",
|
|
384
|
+
"module": "/src/internal/RootElement.ts"
|
|
385
|
+
},
|
|
386
|
+
"tagName": "primitiv-collapsible",
|
|
387
|
+
"customElement": true,
|
|
388
|
+
"summary": "The state owner of a single disclosure: a trigger that shows and hides one panel."
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"kind": "class",
|
|
392
|
+
"description": "`<primitiv-collapsible-trigger>` — an interactive part. It decorates exactly\none child the consumer writes, a `<button>`, which receives `aria-expanded`,\n`aria-controls` and the state attributes, so the rendered DOM matches React's\n`<button aria-expanded>` (RFC 0033 D24).",
|
|
393
|
+
"name": "PrimitivCollapsibleTriggerElement",
|
|
394
|
+
"superclass": {
|
|
395
|
+
"name": "ElementBase",
|
|
396
|
+
"module": "/src/internal/element.ts"
|
|
397
|
+
},
|
|
398
|
+
"tagName": "primitiv-collapsible-trigger",
|
|
399
|
+
"customElement": true
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"kind": "class",
|
|
403
|
+
"description": "`<primitiv-collapsible-content>` — the panel. Structural: the root writes its\nid and state and hides it while closed.",
|
|
404
|
+
"name": "PrimitivCollapsibleContentElement",
|
|
405
|
+
"events": [
|
|
406
|
+
{
|
|
407
|
+
"type": {
|
|
408
|
+
"text": "CustomEvent"
|
|
409
|
+
},
|
|
410
|
+
"description": "Bubbles from the panel as it opens (not on first render), so a lazy panel can fetch its content.",
|
|
411
|
+
"name": "primitiv-collapsible-show"
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"attributes": [
|
|
415
|
+
{
|
|
416
|
+
"type": {
|
|
417
|
+
"text": "boolean"
|
|
418
|
+
},
|
|
419
|
+
"description": "Never sets `hidden`, so styles can animate the panel open and closed. A closed panel always carries `aria-hidden`, so it stays out of the accessibility tree either way.",
|
|
420
|
+
"name": "force-mount"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"type": {
|
|
424
|
+
"text": "string"
|
|
425
|
+
},
|
|
426
|
+
"description": "Shows a clamped preview while closed instead of hiding the panel (the read-more pattern). A bare number is pixels; anything else is a CSS length, used verbatim. Published as the `--primitiv-collapsible-collapsed-height` custom property, with `data-clamped=\"true\"`; the panel is never hidden, since the preview is real content.",
|
|
427
|
+
"name": "collapsed-height"
|
|
428
|
+
}
|
|
429
|
+
],
|
|
430
|
+
"superclass": {
|
|
431
|
+
"name": "ElementBase",
|
|
432
|
+
"module": "/src/internal/element.ts"
|
|
433
|
+
},
|
|
434
|
+
"tagName": "primitiv-collapsible-content",
|
|
435
|
+
"customElement": true
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"kind": "class",
|
|
439
|
+
"description": "`<primitiv-collapsible-trigger-icon>` — a decorative indicator, usually inside\nthe trigger's button. The root hides it from assistive technology and mirrors\nthe `data-state`, for a chevron that flips.",
|
|
440
|
+
"name": "PrimitivCollapsibleTriggerIconElement",
|
|
441
|
+
"superclass": {
|
|
442
|
+
"name": "ElementBase",
|
|
443
|
+
"module": "/src/internal/element.ts"
|
|
444
|
+
},
|
|
445
|
+
"tagName": "primitiv-collapsible-trigger-icon",
|
|
446
|
+
"customElement": true
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"kind": "function",
|
|
450
|
+
"name": "defineCollapsible",
|
|
451
|
+
"return": {
|
|
452
|
+
"type": {
|
|
453
|
+
"text": "void"
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
"parameters": [
|
|
457
|
+
{
|
|
458
|
+
"name": "registry",
|
|
459
|
+
"default": "globalThis.customElements",
|
|
460
|
+
"type": {
|
|
461
|
+
"text": "ElementRegistry | undefined"
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
],
|
|
465
|
+
"description": "Define the four Collapsible elements on `registry` (the global\n`customElements` by default). Safe to call more than once, and a no-op where\nthere is no registry (a server render)."
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
"exports": [
|
|
469
|
+
{
|
|
470
|
+
"kind": "js",
|
|
471
|
+
"name": "ElementRegistry",
|
|
472
|
+
"declaration": {
|
|
473
|
+
"name": "ElementRegistry",
|
|
474
|
+
"module": "src/collapsible/elements.ts"
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"kind": "js",
|
|
479
|
+
"name": "PrimitivCollapsibleElement",
|
|
480
|
+
"declaration": {
|
|
481
|
+
"name": "PrimitivCollapsibleElement",
|
|
482
|
+
"module": "src/collapsible/elements.ts"
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
"kind": "js",
|
|
487
|
+
"name": "PrimitivCollapsibleTriggerElement",
|
|
488
|
+
"declaration": {
|
|
489
|
+
"name": "PrimitivCollapsibleTriggerElement",
|
|
490
|
+
"module": "src/collapsible/elements.ts"
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"kind": "js",
|
|
495
|
+
"name": "PrimitivCollapsibleContentElement",
|
|
496
|
+
"declaration": {
|
|
497
|
+
"name": "PrimitivCollapsibleContentElement",
|
|
498
|
+
"module": "src/collapsible/elements.ts"
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
"kind": "js",
|
|
503
|
+
"name": "PrimitivCollapsibleTriggerIconElement",
|
|
504
|
+
"declaration": {
|
|
505
|
+
"name": "PrimitivCollapsibleTriggerIconElement",
|
|
506
|
+
"module": "src/collapsible/elements.ts"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"kind": "js",
|
|
511
|
+
"name": "defineCollapsible",
|
|
512
|
+
"declaration": {
|
|
513
|
+
"name": "defineCollapsible",
|
|
514
|
+
"module": "src/collapsible/elements.ts"
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
]
|
|
518
|
+
},
|
|
289
519
|
{
|
|
290
520
|
"kind": "javascript-module",
|
|
291
521
|
"path": "src/tabs/elements.ts",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect entry: importing this module defines the four Collapsible
|
|
3
|
+
* elements (`<primitiv-collapsible>`, `-trigger`, `-content`, `-trigger-icon`)
|
|
4
|
+
* on the global `customElements` registry.
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script type="module">import "@primitiv-ui/web/define/collapsible";</script>
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
import { defineCollapsible } from "../collapsible/elements.js";
|
|
11
|
+
defineCollapsible();
|
package/dist/define/index.d.ts
CHANGED
package/dist/define/index.js
CHANGED
|
@@ -11,3 +11,7 @@ export type PrimitivTabsChangeEvent = CustomEvent<{
|
|
|
11
11
|
export type PrimitivAccordionChangeEvent = CustomEvent<{
|
|
12
12
|
value: string[];
|
|
13
13
|
}>;
|
|
14
|
+
/** The `primitiv-collapsible-change` event: bubbles, cancelable, fired before the change applies, with the open state afterwards. */
|
|
15
|
+
export type PrimitivCollapsibleChangeEvent = CustomEvent<{
|
|
16
|
+
open: boolean;
|
|
17
|
+
}>;
|
|
@@ -19,13 +19,14 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { DetailedHTMLProps, HTMLAttributes } from "react";
|
|
21
21
|
import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
|
|
22
|
+
import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
|
|
22
23
|
import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
|
|
23
|
-
import type { PrimitivAccordionChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
|
|
24
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
|
|
24
25
|
/** React's own props for an element, plus `class`, which React 19 passes to custom elements. */
|
|
25
26
|
type ElementProps<E extends HTMLElement> = DetailedHTMLProps<HTMLAttributes<E>, E> & {
|
|
26
27
|
class?: string;
|
|
27
28
|
};
|
|
28
|
-
export type { PrimitivAccordionChangeEvent, PrimitivTabsChangeEvent };
|
|
29
|
+
export type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivTabsChangeEvent };
|
|
29
30
|
declare module "react" {
|
|
30
31
|
namespace JSX {
|
|
31
32
|
interface IntrinsicElements {
|
|
@@ -46,6 +47,18 @@ declare module "react" {
|
|
|
46
47
|
"onprimitiv-accordion-show"?: (event: CustomEvent) => void;
|
|
47
48
|
};
|
|
48
49
|
"primitiv-accordion-trigger-icon": ElementProps<PrimitivAccordionTriggerIconElement>;
|
|
50
|
+
"primitiv-collapsible": ElementProps<PrimitivCollapsibleElement> & {
|
|
51
|
+
open?: boolean;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
"onprimitiv-collapsible-change"?: (event: PrimitivCollapsibleChangeEvent) => void;
|
|
54
|
+
};
|
|
55
|
+
"primitiv-collapsible-trigger": ElementProps<PrimitivCollapsibleTriggerElement>;
|
|
56
|
+
"primitiv-collapsible-content": ElementProps<PrimitivCollapsibleContentElement> & {
|
|
57
|
+
"force-mount"?: boolean;
|
|
58
|
+
"collapsed-height"?: string | number;
|
|
59
|
+
"onprimitiv-collapsible-show"?: (event: CustomEvent) => void;
|
|
60
|
+
};
|
|
61
|
+
"primitiv-collapsible-trigger-icon": ElementProps<PrimitivCollapsibleTriggerIconElement>;
|
|
49
62
|
"primitiv-tabs": ElementProps<PrimitivTabsElement> & {
|
|
50
63
|
value?: string;
|
|
51
64
|
orientation?: "horizontal" | "vertical";
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { HTMLAttributes } from "svelte/elements";
|
|
20
20
|
import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
|
|
21
|
+
import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
|
|
21
22
|
import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
|
|
22
|
-
import type { PrimitivAccordionChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
|
|
23
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
|
|
23
24
|
/** Svelte's own attributes and events for an element. */
|
|
24
25
|
type Attributes<E extends HTMLElement> = HTMLAttributes<E>;
|
|
25
26
|
declare module "svelte/elements" {
|
|
@@ -41,6 +42,18 @@ declare module "svelte/elements" {
|
|
|
41
42
|
"onprimitiv-accordion-show"?: (event: CustomEvent) => void;
|
|
42
43
|
};
|
|
43
44
|
"primitiv-accordion-trigger-icon": Attributes<PrimitivAccordionTriggerIconElement>;
|
|
45
|
+
"primitiv-collapsible": Attributes<PrimitivCollapsibleElement> & {
|
|
46
|
+
open?: boolean;
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
"onprimitiv-collapsible-change"?: (event: PrimitivCollapsibleChangeEvent) => void;
|
|
49
|
+
};
|
|
50
|
+
"primitiv-collapsible-trigger": Attributes<PrimitivCollapsibleTriggerElement>;
|
|
51
|
+
"primitiv-collapsible-content": Attributes<PrimitivCollapsibleContentElement> & {
|
|
52
|
+
"force-mount"?: boolean;
|
|
53
|
+
"collapsed-height"?: string | number;
|
|
54
|
+
"onprimitiv-collapsible-show"?: (event: CustomEvent) => void;
|
|
55
|
+
};
|
|
56
|
+
"primitiv-collapsible-trigger-icon": Attributes<PrimitivCollapsibleTriggerIconElement>;
|
|
44
57
|
"primitiv-tabs": Attributes<PrimitivTabsElement> & {
|
|
45
58
|
value?: string;
|
|
46
59
|
orientation?: "horizontal" | "vertical";
|
package/dist/frameworks/vue.d.ts
CHANGED
|
@@ -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, PrimitivTabsChangeEvent } from "./events.js";
|
|
22
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, 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" {
|
|
@@ -43,6 +43,20 @@ declare module "vue" {
|
|
|
43
43
|
"primitiv-accordion-show": (event: CustomEvent) => void;
|
|
44
44
|
}>;
|
|
45
45
|
"primitiv-accordion-trigger-icon": Tag<Record<never, never>>;
|
|
46
|
+
"primitiv-collapsible": Tag<{
|
|
47
|
+
open?: boolean | "";
|
|
48
|
+
disabled?: boolean | "";
|
|
49
|
+
}, {
|
|
50
|
+
"primitiv-collapsible-change": (event: PrimitivCollapsibleChangeEvent) => void;
|
|
51
|
+
}>;
|
|
52
|
+
"primitiv-collapsible-trigger": Tag<Record<never, never>>;
|
|
53
|
+
"primitiv-collapsible-content": Tag<{
|
|
54
|
+
forceMount?: boolean | "";
|
|
55
|
+
collapsedHeight?: string | number;
|
|
56
|
+
}, {
|
|
57
|
+
"primitiv-collapsible-show": (event: CustomEvent) => void;
|
|
58
|
+
}>;
|
|
59
|
+
"primitiv-collapsible-trigger-icon": Tag<Record<never, never>>;
|
|
46
60
|
"primitiv-tabs": Tag<{
|
|
47
61
|
value?: string;
|
|
48
62
|
orientation?: "horizontal" | "vertical";
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/primitiv-web.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function b(e,t,i){return`${e}-${t}-${i}`}function A({orientation:e,dir:t,homeEnd:i=!1,activate:r=!1}){let n={};if(e==="horizontal"||e==="both"){let c=t==="rtl"?"ArrowLeft":"ArrowRight",d=t==="rtl"?"ArrowRight":"ArrowLeft";n[c]="next",n[d]="prev"}return(e==="vertical"||e==="both")&&(n.ArrowDown="next",n.ArrowUp="prev"),i&&(n.Home="first",n.End="last"),r&&(n.Enter="activate",n[" "]="activate"),n}function E({action:e,navigable:t,currentKey:i}){let r=t.length;if(r===0)return null;switch(e){case"activate":return{target:i};case"first":return{target:t[0]};case"last":return{target:t[r-1]};case void 0:return null;case"next":case"prev":{let n=t.indexOf(i);if(n===-1)return null;let c=e==="next"?1:r-1;return{target:t[(n+c)%r]}}}}function D(e){return e.active??e.values[0]}function R(e,t){return e.disabled.has(t)||e.active===t?null:t}function N(e,t,i){let r=A({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[i],n=E({action:r,navigable:e.values,currentKey:t});if(!n)return null;let c=n.target,d=e.activationMode==="automatic"||r==="activate";return{focus:c,activate:d?R(e,c):null}}function P(e,t){return e.disabled.has(t)?null:e.expanded.includes(t)?e.expanded.filter(i=>i!==t):e.multiple?[...e.expanded,t]:[t]}function $(e,t,i){let r=A({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[i];if(r==="activate")return e.disabled.has(t)?null:{focus:null,toggle:t};let n=e.values.filter(d=>!e.disabled.has(d)),c=E({action:r,navigable:n,currentKey:t});return c&&{focus:c.target,toggle:null}}var v=class{#t;#e=new Map;#i=null;constructor(t){this.#t=t}registerTrigger(t,i,r={}){this.#e.set(i,{value:t,disabled:r.disabled??!1})}setTriggers(t){this.#e.clear();for(let{value:i,element:r,disabled:n}of t)this.registerTrigger(i,r,{disabled:n})}unregisterTrigger(t){this.#e.delete(t)}connect(){if(this.#i)return;this.#i=new AbortController;let{signal:t}=this.#i;this.#t.addEventListener("click",i=>this.#o(i,this.onTriggerClick),{signal:t}),this.#t.addEventListener("keydown",i=>this.#o(i,this.onTriggerKeydown),{signal:t})}disconnect(){this.#i?.abort(),this.#i=null}ordered(){return[...this.#e].sort(([t],[i])=>t.compareDocumentPosition(i)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1)}disabled(){let t=new Set;for(let i of this.#e.values())i.disabled&&t.add(i.value);return t}#o(t,i){for(let[r,n]of this.#e)if(r.contains(t.target))return i.call(this,n,t)}};var y=class extends v{#t;constructor(t,i){super(t),this.#t=i}#e(t){let{expanded:i,multiple:r}=this.#t.state(),n=P({disabled:this.disabled(),expanded:i,multiple:r},t);n!==null&&this.#t.change(n)}onTriggerClick(t){this.#e(t.value)}onTriggerKeydown(t,i){let{expanded:r,multiple:n,orientation:c,dir:d}=this.#t.state(),p=this.ordered(),s=p.map(([,l])=>l.value),o=$({values:s,disabled:this.disabled(),expanded:r,multiple:n,orientation:c,dir:d},t.value,i.key);o&&(i.preventDefault(),o.toggle!==null&&this.#e(o.toggle),o.focus!==null&&p[s.indexOf(o.focus)][0].focus())}};var g=globalThis.HTMLElement??class{};function a(e,t,i){e.getAttribute(t)!==i&&(i===null?e.removeAttribute(t):e.setAttribute(t,i))}var W=new WeakSet;function T(e,t){W.has(e)||(W.add(e),console.error(t,e))}function M(e,t){if(e)for(let[i,r]of t)e.get(i)||e.define(i,r)}function m(e,t,i){return[...e.querySelectorAll(t)].filter(r=>r.closest(i)===e)}var V=0,f=class extends g{#t;#e=new MutationObserver(()=>this.reconcile());connectedCallback(){this.controller.connect(),this.#e.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:[...this.reconcileOn]}),this.reconcile()}disconnectedCallback(){this.controller.disconnect(),this.#e.disconnect()}rootId(){return this.id||(this.#t??=`${this.localName}-${++V}`)}direction(){return this.matches(":dir(rtl)")?"rtl":"ltr"}parts(t){return m(this,t,this.localName)}announce(t,i){return this.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:i}))}};var X="primitiv-accordion",h="primitiv-accordion-item",z="primitiv-accordion-trigger",_="primitiv-accordion-content",j="primitiv-accordion-trigger-icon";function Y(e){return(e??"").split(/\s+/).filter(Boolean)}function Z(e){return e.childElementCount===1?e.firstElementChild:(T(e,`<${z}> needs exactly one element child (a <button>) to decorate.`),null)}var O=class extends f{#t=new Set;#e=!1;controller=new y(this,this.#i());reconcileOn=["value","disabled","orientation","force-mount"];get value(){return Y(this.getAttribute("value"))}set value(t){this.setAttribute("value",typeof t=="string"?t:t.join(" "))}#i(){return{state:()=>({expanded:this.value,multiple:this.hasAttribute("multiple"),orientation:this.#o(),dir:this.direction()}),change:t=>{this.announce("primitiv-accordion-change",{value:t})&&(this.value=t)}}}#o(){return this.getAttribute("orientation")==="horizontal"?"horizontal":"vertical"}reconcile(){let t=new Set(this.value),i=this.rootId();a(this,"data-orientation",this.#o());let r=[];for(let n of this.parts(h)){let c=n.getAttribute("value");if(c===null){T(n,`<${h}> needs a value, which pairs it with the root's value.`);continue}let d=t.has(c),p=d?"open":"closed",[s]=m(n,z,h),[o]=m(n,_,h),l=s?Z(s):null;if(l){let u=s.hasAttribute("disabled");r.push({value:c,element:l,disabled:u}),l.id||(l.id=b(i,"heading",c)),a(l,"aria-expanded",String(d)),a(l,"aria-disabled",String(u)),a(l,"data-disabled",String(u)),a(l,"data-state",p)}if(o){o.id||(o.id=b(i,"panel",c));let u=o.hasAttribute("force-mount");o.hasAttribute("role")||o.setAttribute("role","region"),a(o,"aria-labelledby",l?l.id:null),a(o,"hidden",d||u?null:""),a(o,"aria-hidden",d?null:"true"),a(o,"data-state",p),this.#e&&d&&!this.#t.has(c)&&o.dispatchEvent(new CustomEvent("primitiv-accordion-show",{bubbles:!0}))}l&&a(l,"aria-controls",o?o.id:null);for(let u of m(n,j,h))a(u,"aria-hidden","true"),a(u,"data-state",p)}this.controller.setTriggers(r),this.#t=t,this.#e=!0}},w=class extends g{},C=class extends g{},K=class extends g{},H=class extends g{};function G(e=globalThis.customElements){M(e,[[X,O],[h,w],[z,C],[_,K],[j,H]])}var x=class extends v{#t;constructor(t,i){super(t),this.#t=i}onTriggerClick(t){let{active:i}=this.#t.state(),r=R({disabled:this.disabled(),active:i},t.value);if(r!==null){let n=this.ordered().map(([,c])=>c.value);this.#t.activate(r,n.indexOf(r))}}onTriggerKeydown(t,i){let{active:r,orientation:n,dir:c,activationMode:d}=this.#t.state(),p=this.ordered(),s=p.map(([,l])=>l.value),o=N({values:s,disabled:this.disabled(),active:r,orientation:n,dir:c,activationMode:d},t.value,i.key);o&&(i.preventDefault(),o.activate!==null&&this.#t.activate(o.activate,s.indexOf(o.activate)),p[s.indexOf(o.focus)][0].focus())}};var tt="primitiv-tabs",J="primitiv-tabs-list",B="primitiv-tabs-trigger",Q="primitiv-tabs-content";function et(e){let t=e.getAttribute("value");return e.childElementCount===1&&t!==null?{tab:e.firstElementChild,value:t}:(T(e,`<${B}> needs a value and exactly one element child (a <button>, an <a href> or a router link) to decorate.`),null)}var L=class extends f{#t;#e=!1;controller=new x(this,this.#i());reconcileOn=["value","disabled","label","orientation"];get value(){return this.getAttribute("value")??void 0}set value(t){this.setAttribute("value",t)}#i(){return{state:()=>({active:this.value,orientation:this.#n(),dir:this.direction(),activationMode:this.#o()}),activate:(t,i)=>{this.announce("primitiv-tabs-change",{value:t,index:i})&&(this.value=t)}}}#o(){let t=this.getAttribute("activation-mode");return t==="manual"?t:"automatic"}#n(){return this.getAttribute("orientation")==="vertical"?"vertical":"horizontal"}reconcile(){let t=this.#n(),i=this.value,r=this.rootId();a(this,"data-orientation",t);for(let s of this.parts(J)){a(s,"role","tablist"),a(s,"aria-orientation",t),a(s,"data-orientation",t);let o=s.getAttribute("label");o!==null&&a(s,"aria-label",o)}let n=new Map;for(let s of this.parts(Q)){let o=s.getAttribute("value");o!==null&&n.set(o,s)}let c=this.parts(B).flatMap(s=>{let o=et(s);return o?[{trigger:s,...o}]:[]}),d=D({values:c.map(s=>s.value),active:i});this.controller.setTriggers(c.map(({trigger:s,tab:o,value:l})=>({value:l,element:o,disabled:s.hasAttribute("disabled")})));for(let{trigger:s,tab:o,value:l}of c){let u=n.get(l),F=l===i,U=s.hasAttribute("disabled");o.id||(o.id=b(r,"trigger",l)),u&&!u.id&&(u.id=b(r,"panel",l)),a(o,"role","tab"),a(o,"aria-selected",String(F)),a(o,"aria-controls",u?u.id:null),a(o,"tabindex",l===d?"0":"-1"),a(o,"aria-disabled",U?"true":null),a(o,"data-disabled",U?"":null),a(o,"data-state",F?"active":"inactive"),a(o,"data-orientation",t),u&&a(u,"aria-labelledby",o.id)}for(let[s,o]of n){let l=s===i;a(o,"role","tabpanel"),a(o,"tabindex","0"),a(o,"hidden",l?null:""),a(o,"data-state",l?"active":"inactive"),a(o,"data-orientation",t)}let p=n.get(i);this.#e&&i!==this.#t&&p&&p.dispatchEvent(new CustomEvent("primitiv-tabs-show",{bubbles:!0})),this.#t=i,this.#e=!0}},S=class extends g{},k=class extends g{},I=class extends g{};function q(e=globalThis.customElements){M(e,[[tt,L],[J,S],[B,k],[Q,I]])}G();q();export{y as AccordionController,K as PrimitivAccordionContentElement,O as PrimitivAccordionElement,w as PrimitivAccordionItemElement,C as PrimitivAccordionTriggerElement,H as PrimitivAccordionTriggerIconElement,I as PrimitivTabsContentElement,L as PrimitivTabsElement,S as PrimitivTabsListElement,k as PrimitivTabsTriggerElement,x as TabsController,G as defineAccordion,q as defineTabs};
|
|
1
|
+
function h(e,t,o){return`${e}-${t}-${o}`}function C({orientation:e,dir:t,homeEnd:o=!1,activate:r=!1}){let s={};if(e==="horizontal"||e==="both"){let c=t==="rtl"?"ArrowLeft":"ArrowRight",a=t==="rtl"?"ArrowRight":"ArrowLeft";s[c]="next",s[a]="prev"}return(e==="vertical"||e==="both")&&(s.ArrowDown="next",s.ArrowUp="prev"),o&&(s.Home="first",s.End="last"),r&&(s.Enter="activate",s[" "]="activate"),s}function w({action:e,navigable:t,currentKey:o}){let r=t.length;if(r===0)return null;switch(e){case"activate":return{target:o};case"first":return{target:t[0]};case"last":return{target:t[r-1]};case void 0:return null;case"next":case"prev":{let s=t.indexOf(o);if(s===-1)return null;let c=e==="next"?1:r-1;return{target:t[(s+c)%r]}}}}function B(e){return e.active??e.values[0]}function O(e,t){return e.disabled.has(t)||e.active===t?null:t}function q(e,t,o){let r=C({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[o],s=w({action:r,navigable:e.values,currentKey:t});if(!s)return null;let c=s.target,a=e.activationMode==="automatic"||r==="activate";return{focus:c,activate:a?O(e,c):null}}function F(e,t){return e.disabled.has(t)?null:e.expanded.includes(t)?e.expanded.filter(o=>o!==t):e.multiple?[...e.expanded,t]:[t]}function U(e,t,o){let r=C({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[o];if(r==="activate")return e.disabled.has(t)?null:{focus:null,toggle:t};let s=e.values.filter(a=>!e.disabled.has(a)),c=w({action:r,navigable:s,currentKey:t});return c&&{focus:c.target,toggle:null}}function R(e){return e.disabled?null:!e.open}function W(e,t){if(t!=="Enter"&&t!==" ")return null;let o=R(e);return o===null?null:{open:o}}var b=class{#t;#e=new Map;#o=null;constructor(t){this.#t=t}registerTrigger(t,o,r={}){this.#e.set(o,{value:t,disabled:r.disabled??!1})}setTriggers(t){this.#e.clear();for(let{value:o,element:r,disabled:s}of t)this.registerTrigger(o,r,{disabled:s})}unregisterTrigger(t){this.#e.delete(t)}connect(){if(this.#o)return;this.#o=new AbortController;let{signal:t}=this.#o;this.#t.addEventListener("click",o=>this.#i(o,this.onTriggerClick),{signal:t}),this.#t.addEventListener("keydown",o=>this.#i(o,this.onTriggerKeydown),{signal:t})}disconnect(){this.#o?.abort(),this.#o=null}ordered(){return[...this.#e].sort(([t],[o])=>t.compareDocumentPosition(o)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1)}disabled(){let t=new Set;for(let o of this.#e.values())o.disabled&&t.add(o.value);return t}#i(t,o){for(let[r,s]of this.#e)if(r.contains(t.target))return o.call(this,s,t)}};var x=class extends b{#t;constructor(t,o){super(t),this.#t=o}#e(t){let{expanded:o,multiple:r}=this.#t.state(),s=F({disabled:this.disabled(),expanded:o,multiple:r},t);s!==null&&this.#t.change(s)}onTriggerClick(t){this.#e(t.value)}onTriggerKeydown(t,o){let{expanded:r,multiple:s,orientation:c,dir:a}=this.#t.state(),p=this.ordered(),l=p.map(([,d])=>d.value),i=U({values:l,disabled:this.disabled(),expanded:r,multiple:s,orientation:c,dir:a},t.value,o.key);i&&(o.preventDefault(),i.toggle!==null&&this.#e(i.toggle),i.focus!==null&&p[l.indexOf(i.focus)][0].focus())}};var g=globalThis.HTMLElement??class{};function n(e,t,o){e.getAttribute(t)!==o&&(o===null?e.removeAttribute(t):e.setAttribute(t,o))}var tt=new WeakSet;function f(e,t){tt.has(e)||(tt.add(e),console.error(t,e))}function v(e,t){if(e)for(let[o,r]of t)e.get(o)||e.define(o,r)}function y(e,t,o){return[...e.querySelectorAll(t)].filter(r=>r.closest(o)===e)}var lt=0,m=class extends g{#t;#e=new MutationObserver(()=>this.reconcile());connectedCallback(){this.controller.connect(),this.#e.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:[...this.reconcileOn]}),this.reconcile()}disconnectedCallback(){this.controller.disconnect(),this.#e.disconnect()}rootId(){return this.id||(this.#t??=`${this.localName}-${++lt}`)}direction(){return this.matches(":dir(rtl)")?"rtl":"ltr"}parts(t){return y(this,t,this.localName)}announce(t,o){return this.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:o}))}};var at="primitiv-accordion",T="primitiv-accordion-item",_="primitiv-accordion-trigger",et="primitiv-accordion-content",ot="primitiv-accordion-trigger-icon";function ct(e){return(e??"").split(/\s+/).filter(Boolean)}function dt(e){return e.childElementCount===1?e.firstElementChild:(f(e,`<${_}> needs exactly one element child (a <button>) to decorate.`),null)}var M=class extends m{#t=new Set;#e=!1;controller=new x(this,this.#o());reconcileOn=["value","disabled","orientation","force-mount"];get value(){return ct(this.getAttribute("value"))}set value(t){this.setAttribute("value",typeof t=="string"?t:t.join(" "))}#o(){return{state:()=>({expanded:this.value,multiple:this.hasAttribute("multiple"),orientation:this.#i(),dir:this.direction()}),change:t=>{this.announce("primitiv-accordion-change",{value:t})&&(this.value=t)}}}#i(){return this.getAttribute("orientation")==="horizontal"?"horizontal":"vertical"}reconcile(){let t=new Set(this.value),o=this.rootId();n(this,"data-orientation",this.#i());let r=[];for(let s of this.parts(T)){let c=s.getAttribute("value");if(c===null){f(s,`<${T}> needs a value, which pairs it with the root's value.`);continue}let a=t.has(c),p=a?"open":"closed",[l]=y(s,_,T),[i]=y(s,et,T),d=l?dt(l):null;if(d){let u=l.hasAttribute("disabled");r.push({value:c,element:d,disabled:u}),d.id||(d.id=h(o,"heading",c)),n(d,"aria-expanded",String(a)),n(d,"aria-disabled",String(u)),n(d,"data-disabled",String(u)),n(d,"data-state",p)}if(i){i.id||(i.id=h(o,"panel",c));let u=i.hasAttribute("force-mount");i.hasAttribute("role")||i.setAttribute("role","region"),n(i,"aria-labelledby",d?d.id:null),n(i,"hidden",a||u?null:""),n(i,"aria-hidden",a?null:"true"),n(i,"data-state",p),this.#e&&a&&!this.#t.has(c)&&i.dispatchEvent(new CustomEvent("primitiv-accordion-show",{bubbles:!0}))}d&&n(d,"aria-controls",i?i.id:null);for(let u of y(s,ot,T))n(u,"aria-hidden","true"),n(u,"data-state",p)}this.controller.setTriggers(r),this.#t=t,this.#e=!0}},H=class extends g{},K=class extends g{},L=class extends g{},S=class extends g{};function j(e=globalThis.customElements){v(e,[[at,M],[T,H],[_,K],[et,L],[ot,S]])}var E=class extends b{#t;constructor(t,o){super(t),this.#t=o}onTriggerClick(t){let o=R({open:this.#t.state().open,disabled:t.disabled});o!==null&&this.#t.change(o)}onTriggerKeydown(t,o){let r=W({open:this.#t.state().open,disabled:t.disabled},o.key);r&&(o.preventDefault(),this.#t.change(r.open))}};var pt="primitiv-collapsible",V="primitiv-collapsible-trigger",it="primitiv-collapsible-content",nt="primitiv-collapsible-trigger-icon",ut="--primitiv-collapsible-collapsed-height";function gt(e){return e.childElementCount===1?e.firstElementChild:(f(e,`<${V}> needs exactly one element child (a <button>) to decorate.`),null)}function bt(e){return Number.isNaN(Number(e))?e:`${e}px`}function mt(e,t,o){e.style.getPropertyValue(t)!==o&&(e.style.setProperty(t,o),e.getAttribute("style")===""&&e.removeAttribute("style"))}var I=class extends m{#t;controller=new E(this,this.#e());reconcileOn=["open","disabled","force-mount","collapsed-height"];get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",t)}#e(){return{state:()=>({open:this.open}),change:t=>{this.announce("primitiv-collapsible-change",{open:t})&&(this.open=t)}}}reconcile(){let t=this.open,o=t?"open":"closed",r=this.hasAttribute("disabled"),s=this.rootId();n(this,"data-state",o),n(this,"data-disabled",String(r));let[c]=this.parts(V),[a]=this.parts(it),p=c?gt(c):null;if(p&&(p.id||(p.id=`${s}-trigger`),n(p,"aria-expanded",String(t)),n(p,"aria-disabled",r?"true":null),n(p,"data-disabled",String(r)),n(p,"data-state",o)),a){a.id||(a.id=`${s}-content`);let l=a.getAttribute("collapsed-height"),i=l!==null,d=i||a.hasAttribute("force-mount");n(a,"hidden",t||d?null:""),n(a,"aria-hidden",t||i?null:"true"),n(a,"data-state",o),n(a,"data-disabled",String(r)),n(a,"data-clamped",i?"true":null),mt(a,ut,i?bt(l):""),t&&this.#t===!1&&a.dispatchEvent(new CustomEvent("primitiv-collapsible-show",{bubbles:!0}))}p&&n(p,"aria-controls",a?a.id:null);for(let l of this.parts(nt))n(l,"aria-hidden","true"),n(l,"data-state",o);this.controller.setTriggers(p?[{value:"trigger",element:p,disabled:r}]:[]),this.#t=t}},k=class extends g{},N=class extends g{},D=class extends g{};function J(e=globalThis.customElements){v(e,[[pt,I],[V,k],[it,N],[nt,D]])}var A=class extends b{#t;constructor(t,o){super(t),this.#t=o}onTriggerClick(t){let{active:o}=this.#t.state(),r=O({disabled:this.disabled(),active:o},t.value);if(r!==null){let s=this.ordered().map(([,c])=>c.value);this.#t.activate(r,s.indexOf(r))}}onTriggerKeydown(t,o){let{active:r,orientation:s,dir:c,activationMode:a}=this.#t.state(),p=this.ordered(),l=p.map(([,d])=>d.value),i=q({values:l,disabled:this.disabled(),active:r,orientation:s,dir:c,activationMode:a},t.value,o.key);i&&(o.preventDefault(),i.activate!==null&&this.#t.activate(i.activate,l.indexOf(i.activate)),p[l.indexOf(i.focus)][0].focus())}};var ht="primitiv-tabs",rt="primitiv-tabs-list",Q="primitiv-tabs-trigger",st="primitiv-tabs-content";function ft(e){let t=e.getAttribute("value");return e.childElementCount===1&&t!==null?{tab:e.firstElementChild,value:t}:(f(e,`<${Q}> needs a value and exactly one element child (a <button>, an <a href> or a router link) to decorate.`),null)}var P=class extends m{#t;#e=!1;controller=new A(this,this.#o());reconcileOn=["value","disabled","label","orientation"];get value(){return this.getAttribute("value")??void 0}set value(t){this.setAttribute("value",t)}#o(){return{state:()=>({active:this.value,orientation:this.#n(),dir:this.direction(),activationMode:this.#i()}),activate:(t,o)=>{this.announce("primitiv-tabs-change",{value:t,index:o})&&(this.value=t)}}}#i(){let t=this.getAttribute("activation-mode");return t==="manual"?t:"automatic"}#n(){return this.getAttribute("orientation")==="vertical"?"vertical":"horizontal"}reconcile(){let t=this.#n(),o=this.value,r=this.rootId();n(this,"data-orientation",t);for(let l of this.parts(rt)){n(l,"role","tablist"),n(l,"aria-orientation",t),n(l,"data-orientation",t);let i=l.getAttribute("label");i!==null&&n(l,"aria-label",i)}let s=new Map;for(let l of this.parts(st)){let i=l.getAttribute("value");i!==null&&s.set(i,l)}let c=this.parts(Q).flatMap(l=>{let i=ft(l);return i?[{trigger:l,...i}]:[]}),a=B({values:c.map(l=>l.value),active:o});this.controller.setTriggers(c.map(({trigger:l,tab:i,value:d})=>({value:d,element:i,disabled:l.hasAttribute("disabled")})));for(let{trigger:l,tab:i,value:d}of c){let u=s.get(d),Y=d===o,Z=l.hasAttribute("disabled");i.id||(i.id=h(r,"trigger",d)),u&&!u.id&&(u.id=h(r,"panel",d)),n(i,"role","tab"),n(i,"aria-selected",String(Y)),n(i,"aria-controls",u?u.id:null),n(i,"tabindex",d===a?"0":"-1"),n(i,"aria-disabled",Z?"true":null),n(i,"data-disabled",Z?"":null),n(i,"data-state",Y?"active":"inactive"),n(i,"data-orientation",t),u&&n(u,"aria-labelledby",i.id)}for(let[l,i]of s){let d=l===o;n(i,"role","tabpanel"),n(i,"tabindex","0"),n(i,"hidden",d?null:""),n(i,"data-state",d?"active":"inactive"),n(i,"data-orientation",t)}let p=s.get(o);this.#e&&o!==this.#t&&p&&p.dispatchEvent(new CustomEvent("primitiv-tabs-show",{bubbles:!0})),this.#t=o,this.#e=!0}},$=class extends g{},G=class extends g{},z=class extends g{};function X(e=globalThis.customElements){v(e,[[ht,P],[rt,$],[Q,G],[st,z]])}j();J();X();export{x as AccordionController,E as CollapsibleController,L as PrimitivAccordionContentElement,M as PrimitivAccordionElement,H as PrimitivAccordionItemElement,K as PrimitivAccordionTriggerElement,S as PrimitivAccordionTriggerIconElement,N as PrimitivCollapsibleContentElement,I as PrimitivCollapsibleElement,k as PrimitivCollapsibleTriggerElement,D as PrimitivCollapsibleTriggerIconElement,z as PrimitivTabsContentElement,P as PrimitivTabsElement,$ as PrimitivTabsListElement,G as PrimitivTabsTriggerElement,A as TabsController,j as defineAccordion,J as defineCollapsible,X as defineTabs};
|
package/dist/tags.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* JSR does not allow a published module to do (RFC 0033 §5.6.4).
|
|
14
14
|
*/
|
|
15
15
|
import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "./accordion/elements.js";
|
|
16
|
+
import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "./collapsible/elements.js";
|
|
16
17
|
import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "./tabs/elements.js";
|
|
17
18
|
declare global {
|
|
18
19
|
interface HTMLElementTagNameMap {
|
|
@@ -21,6 +22,10 @@ declare global {
|
|
|
21
22
|
"primitiv-accordion-trigger": PrimitivAccordionTriggerElement;
|
|
22
23
|
"primitiv-accordion-content": PrimitivAccordionContentElement;
|
|
23
24
|
"primitiv-accordion-trigger-icon": PrimitivAccordionTriggerIconElement;
|
|
25
|
+
"primitiv-collapsible": PrimitivCollapsibleElement;
|
|
26
|
+
"primitiv-collapsible-trigger": PrimitivCollapsibleTriggerElement;
|
|
27
|
+
"primitiv-collapsible-content": PrimitivCollapsibleContentElement;
|
|
28
|
+
"primitiv-collapsible-trigger-icon": PrimitivCollapsibleTriggerIconElement;
|
|
24
29
|
"primitiv-tabs": PrimitivTabsElement;
|
|
25
30
|
"primitiv-tabs-list": PrimitivTabsListElement;
|
|
26
31
|
"primitiv-tabs-trigger": PrimitivTabsTriggerElement;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitiv-ui/web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
4
4
|
"description": "Primitiv's headless components as standard custom elements: light DOM, no framework, no runtime dependencies. Works in plain HTML, server-rendered stacks, React, Vue, Angular and anything else that renders HTML.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"types": "./dist/accordion/index.d.ts",
|
|
15
15
|
"default": "./dist/accordion/index.js"
|
|
16
16
|
},
|
|
17
|
+
"./collapsible": {
|
|
18
|
+
"types": "./dist/collapsible/index.d.ts",
|
|
19
|
+
"default": "./dist/collapsible/index.js"
|
|
20
|
+
},
|
|
17
21
|
"./tabs": {
|
|
18
22
|
"types": "./dist/tabs/index.d.ts",
|
|
19
23
|
"default": "./dist/tabs/index.js"
|
|
@@ -26,6 +30,10 @@
|
|
|
26
30
|
"types": "./dist/define/accordion.d.ts",
|
|
27
31
|
"default": "./dist/define/accordion.js"
|
|
28
32
|
},
|
|
33
|
+
"./define/collapsible": {
|
|
34
|
+
"types": "./dist/define/collapsible.d.ts",
|
|
35
|
+
"default": "./dist/define/collapsible.js"
|
|
36
|
+
},
|
|
29
37
|
"./define/tabs": {
|
|
30
38
|
"types": "./dist/define/tabs.d.ts",
|
|
31
39
|
"default": "./dist/define/tabs.js"
|
|
@@ -60,7 +68,7 @@
|
|
|
60
68
|
"directory": "packages/web"
|
|
61
69
|
},
|
|
62
70
|
"dependencies": {
|
|
63
|
-
"@primitiv-ui/core": "0.1.
|
|
71
|
+
"@primitiv-ui/core": "0.1.47"
|
|
64
72
|
},
|
|
65
73
|
"devDependencies": {
|
|
66
74
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function b(e,t,r){return`${e}-${t}-${r}`}function s({orientation:e,dir:t,homeEnd:r=!1,activate:n=!1}){let o={};if(e==="horizontal"||e==="both"){let i=t==="rtl"?"ArrowLeft":"ArrowRight",a=t==="rtl"?"ArrowRight":"ArrowLeft";o[i]="next",o[a]="prev"}return(e==="vertical"||e==="both")&&(o.ArrowDown="next",o.ArrowUp="prev"),r&&(o.Home="first",o.End="last"),n&&(o.Enter="activate",o[" "]="activate"),o}function c({action:e,navigable:t,currentKey:r}){let n=t.length;if(n===0)return null;switch(e){case"activate":return{target:r};case"first":return{target:t[0]};case"last":return{target:t[n-1]};case void 0:return null;case"next":case"prev":{let o=t.indexOf(r);if(o===-1)return null;let i=e==="next"?1:n-1;return{target:t[(o+i)%n]}}}}function y(e){return e.active??e.values[0]}function l(e,t){return e.disabled.has(t)||e.active===t?null:t}function f(e,t,r){let n=s({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[r],o=c({action:n,navigable:e.values,currentKey:t});if(!o)return null;let i=o.target,a=e.activationMode==="automatic"||n==="activate";return{focus:i,activate:a?l(e,i):null}}function m(e,t){return e.disabled.has(t)?null:e.expanded.includes(t)?e.expanded.filter(r=>r!==t):e.multiple?[...e.expanded,t]:[t]}function T(e,t,r){let n=s({orientation:e.orientation,dir:e.dir,homeEnd:!0,activate:!0})[r];if(n==="activate")return e.disabled.has(t)?null:{focus:null,toggle:t};let o=e.values.filter(a=>!e.disabled.has(a)),i=c({action:n,navigable:o,currentKey:t});return i&&{focus:i.target,toggle:null}}var g=globalThis.HTMLElement??class{};function D(e,t,r){e.getAttribute(t)!==r&&(r===null?e.removeAttribute(t):e.setAttribute(t,r))}var d=new WeakSet;function I(e,t){d.has(e)||(d.add(e),console.error(t,e))}function N(e,t){if(e)for(let[r,n]of t)e.get(r)||e.define(r,n)}function u(e,t,r){return[...e.querySelectorAll(t)].filter(n=>n.closest(r)===e)}var h=0,p=class extends g{#e;#t=new MutationObserver(()=>this.reconcile());connectedCallback(){this.controller.connect(),this.#t.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:[...this.reconcileOn]}),this.reconcile()}disconnectedCallback(){this.controller.disconnect(),this.#t.disconnect()}rootId(){return this.id||(this.#e??=`${this.localName}-${++h}`)}direction(){return this.matches(":dir(rtl)")?"rtl":"ltr"}parts(t){return u(this,t,this.localName)}announce(t,r){return this.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:r}))}};var v=class{#e;#t=new Map;#r=null;constructor(t){this.#e=t}registerTrigger(t,r,n={}){this.#t.set(r,{value:t,disabled:n.disabled??!1})}setTriggers(t){this.#t.clear();for(let{value:r,element:n,disabled:o}of t)this.registerTrigger(r,n,{disabled:o})}unregisterTrigger(t){this.#t.delete(t)}connect(){if(this.#r)return;this.#r=new AbortController;let{signal:t}=this.#r;this.#e.addEventListener("click",r=>this.#n(r,this.onTriggerClick),{signal:t}),this.#e.addEventListener("keydown",r=>this.#n(r,this.onTriggerKeydown),{signal:t})}disconnect(){this.#r?.abort(),this.#r=null}ordered(){return[...this.#t].sort(([t],[r])=>t.compareDocumentPosition(r)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1)}disabled(){let t=new Set;for(let r of this.#t.values())r.disabled&&t.add(r.value);return t}#n(t,r){for(let[n,o]of this.#t)if(n.contains(t.target))return r.call(this,o,t)}};export{b as a,y as b,l as c,f as d,m as e,T as f,g,D as h,I as i,N as j,u as k,p as l,v as m};
|