@data-slot/accordion 0.2.150 → 0.2.151
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 +157 -63
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,14 +11,23 @@ npm install @data-slot/accordion
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```html
|
|
14
|
-
<div data-slot="accordion">
|
|
14
|
+
<div data-slot="accordion" data-default-value="one">
|
|
15
15
|
<div data-slot="accordion-item" data-value="one">
|
|
16
|
-
<button data-slot="accordion-trigger">
|
|
17
|
-
|
|
16
|
+
<button data-slot="accordion-trigger">
|
|
17
|
+
<span>Section One</span>
|
|
18
|
+
<svg data-slot="accordion-trigger-icon" viewBox="0 0 12 12" aria-hidden="true">
|
|
19
|
+
<path d="M6.75 0H5.25V5.25H0V6.75H5.25V12H6.75V6.75H12V5.25H6.75V0Z" />
|
|
20
|
+
</svg>
|
|
21
|
+
</button>
|
|
22
|
+
<div data-slot="accordion-content">
|
|
23
|
+
<div data-slot="accordion-content-inner">Content for section one</div>
|
|
24
|
+
</div>
|
|
18
25
|
</div>
|
|
19
26
|
<div data-slot="accordion-item" data-value="two">
|
|
20
27
|
<button data-slot="accordion-trigger">Section Two</button>
|
|
21
|
-
<div data-slot="accordion-content">
|
|
28
|
+
<div data-slot="accordion-content">
|
|
29
|
+
<div data-slot="accordion-content-inner">Content for section two</div>
|
|
30
|
+
</div>
|
|
22
31
|
</div>
|
|
23
32
|
</div>
|
|
24
33
|
|
|
@@ -51,117 +60,204 @@ import { createAccordion } from "@data-slot/accordion";
|
|
|
51
60
|
const accordion = createAccordion(element, {
|
|
52
61
|
multiple: true,
|
|
53
62
|
defaultValue: ["one"],
|
|
54
|
-
|
|
63
|
+
orientation: "vertical",
|
|
64
|
+
loopFocus: true,
|
|
65
|
+
hiddenUntilFound: false,
|
|
55
66
|
onValueChange: (values) => console.log(values),
|
|
56
67
|
});
|
|
57
68
|
```
|
|
58
69
|
|
|
59
70
|
### Options
|
|
60
71
|
|
|
61
|
-
| Option
|
|
62
|
-
|
|
|
63
|
-
| `multiple`
|
|
64
|
-
| `defaultValue`
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
72
|
+
| Option | Type | Default | Description |
|
|
73
|
+
| --- | --- | --- | --- |
|
|
74
|
+
| `multiple` | `boolean` | `false` | Allow multiple items open at once |
|
|
75
|
+
| `defaultValue` | `string \| string[]` | `undefined` | Initially expanded item(s) |
|
|
76
|
+
| `disabled` | `boolean` | `false` | Disable all user interaction for the accordion |
|
|
77
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"vertical"` | Controls roving-focus arrow keys |
|
|
78
|
+
| `loopFocus` | `boolean` | `true` | Wrap roving focus at the ends |
|
|
79
|
+
| `hiddenUntilFound` | `boolean` | `false` | Use `hidden="until-found"` on closed panels |
|
|
80
|
+
| `onValueChange` | `(value: string[]) => void` | `undefined` | Callback when expanded items change |
|
|
81
|
+
| `collapsible` | `boolean` | `true` | Deprecated single-mode alias for “can close the last open item” |
|
|
82
|
+
|
|
83
|
+
### Deprecated Option
|
|
84
|
+
|
|
85
|
+
The following option is deprecated and will be removed in the next major release:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
createAccordion(element, {
|
|
89
|
+
// Deprecated: use the default Base UI-style collapsible behavior instead.
|
|
90
|
+
collapsible: false,
|
|
91
|
+
});
|
|
92
|
+
```
|
|
67
93
|
|
|
68
94
|
### Data Attributes
|
|
69
95
|
|
|
70
96
|
Options can also be set via data attributes on the root element. JS options take precedence.
|
|
71
97
|
|
|
72
98
|
| Attribute | Type | Default | Description |
|
|
73
|
-
|
|
74
|
-
| `data-multiple` | boolean | `false` | Allow multiple items open at once |
|
|
75
|
-
| `data-default-value` | string | none | Initially expanded item |
|
|
76
|
-
| `data-
|
|
99
|
+
| --- | --- | --- | --- |
|
|
100
|
+
| `data-multiple` | `boolean` | `false` | Allow multiple items open at once |
|
|
101
|
+
| `data-default-value` | `string` | none | Initially expanded item |
|
|
102
|
+
| `data-disabled` | `boolean` | `false` | Disable the entire accordion |
|
|
103
|
+
| `data-orientation` | `"horizontal" \| "vertical"` | `"vertical"` | Controls roving-focus arrow keys |
|
|
104
|
+
| `data-loop-focus` | `boolean` | `true` | Wrap roving focus at the ends |
|
|
105
|
+
| `data-hidden-until-found` | `boolean` | `false` | Use `hidden="until-found"` on closed panels |
|
|
106
|
+
| `data-collapsible` | `boolean` | `true` | Deprecated single-mode compatibility alias |
|
|
77
107
|
|
|
78
108
|
Boolean attributes: present or `"true"` = true, `"false"` = false, absent = default.
|
|
79
109
|
|
|
80
110
|
```html
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<div data-slot="accordion" data-collapsible="false">
|
|
111
|
+
<div
|
|
112
|
+
data-slot="accordion"
|
|
113
|
+
data-multiple
|
|
114
|
+
data-default-value="one"
|
|
115
|
+
data-orientation="horizontal"
|
|
116
|
+
>
|
|
88
117
|
...
|
|
89
118
|
</div>
|
|
90
119
|
```
|
|
91
120
|
|
|
92
121
|
### Controller
|
|
93
122
|
|
|
94
|
-
| Method/Property
|
|
95
|
-
|
|
|
96
|
-
| `expand(value)`
|
|
97
|
-
| `collapse(value)` | Collapse an item by value
|
|
98
|
-
| `toggle(value)`
|
|
99
|
-
| `value`
|
|
100
|
-
| `destroy()`
|
|
123
|
+
| Method/Property | Description |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| `expand(value)` | Expand an item by value |
|
|
126
|
+
| `collapse(value)` | Collapse an item by value |
|
|
127
|
+
| `toggle(value)` | Toggle an item by value |
|
|
128
|
+
| `value` | Currently expanded values (readonly `string[]`) |
|
|
129
|
+
| `destroy()` | Cleanup all event listeners |
|
|
101
130
|
|
|
102
131
|
## Markup Structure
|
|
103
132
|
|
|
104
133
|
```html
|
|
105
134
|
<div data-slot="accordion">
|
|
106
135
|
<div data-slot="accordion-item" data-value="unique-id">
|
|
107
|
-
<button data-slot="accordion-trigger">
|
|
108
|
-
|
|
136
|
+
<button data-slot="accordion-trigger">
|
|
137
|
+
<span>Trigger</span>
|
|
138
|
+
<span data-slot="accordion-trigger-icon">+</span>
|
|
139
|
+
</button>
|
|
140
|
+
<div data-slot="accordion-content">
|
|
141
|
+
<div data-slot="accordion-content-inner">Content</div>
|
|
142
|
+
</div>
|
|
109
143
|
</div>
|
|
110
144
|
</div>
|
|
111
145
|
```
|
|
112
146
|
|
|
147
|
+
`data-slot="accordion-trigger-icon"` and `data-slot="accordion-content-inner"` are optional styling hooks.
|
|
148
|
+
|
|
113
149
|
## Styling
|
|
114
150
|
|
|
115
|
-
|
|
151
|
+
### State Hooks
|
|
152
|
+
|
|
153
|
+
The accordion exposes these useful styling hooks:
|
|
154
|
+
|
|
155
|
+
| Element | Hooks |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| root | `data-disabled`, `data-orientation` |
|
|
158
|
+
| item | `data-state`, `data-open`, `data-closed`, `data-index`, `data-disabled` |
|
|
159
|
+
| trigger | `data-state`, `data-panel-open`, `data-disabled`, `aria-expanded` |
|
|
160
|
+
| content | `data-state`, `data-open`, `data-closed`, `data-index`, `data-disabled`, `data-orientation`, `data-starting-style`, `data-ending-style` |
|
|
161
|
+
|
|
162
|
+
### CSS Variables
|
|
163
|
+
|
|
164
|
+
The content element exposes size variables for height or width transitions:
|
|
165
|
+
|
|
166
|
+
| Variable | Description |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `--accordion-panel-height` | Panel height (`auto` at rest, measured px during transitions, `0px` when closed) |
|
|
169
|
+
| `--accordion-panel-width` | Panel width (`auto` at rest, measured px during transitions, `0px` when closed) |
|
|
170
|
+
|
|
171
|
+
### CSS Example
|
|
116
172
|
|
|
117
173
|
```css
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
display: none;
|
|
174
|
+
[data-slot="accordion-item"] {
|
|
175
|
+
border-bottom: 1px solid #e5e7eb;
|
|
121
176
|
}
|
|
122
177
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
display:
|
|
178
|
+
[data-slot="accordion-trigger"] {
|
|
179
|
+
width: 100%;
|
|
180
|
+
display: flex;
|
|
181
|
+
align-items: center;
|
|
182
|
+
gap: 1rem;
|
|
183
|
+
padding: 1rem;
|
|
184
|
+
background: transparent;
|
|
185
|
+
border: 0;
|
|
186
|
+
text-align: left;
|
|
126
187
|
}
|
|
127
188
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
189
|
+
[data-slot="accordion-trigger-icon"] {
|
|
190
|
+
margin-left: auto;
|
|
191
|
+
width: 1rem;
|
|
192
|
+
height: 1rem;
|
|
193
|
+
color: #6b7280;
|
|
194
|
+
transition: transform 0.2s ease;
|
|
133
195
|
}
|
|
134
196
|
|
|
135
|
-
[data-slot="accordion-item"][data-state="open"] {
|
|
136
|
-
|
|
197
|
+
[data-slot="accordion-item"][data-state="open"] [data-slot="accordion-trigger-icon"] {
|
|
198
|
+
transform: rotate(45deg);
|
|
137
199
|
}
|
|
138
200
|
|
|
139
201
|
[data-slot="accordion-content"] {
|
|
140
202
|
overflow: hidden;
|
|
203
|
+
height: var(--accordion-panel-height);
|
|
204
|
+
transition: height 0.2s ease;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
[data-slot="accordion-content"][data-starting-style] {
|
|
208
|
+
height: 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
[data-slot="accordion-content-inner"] {
|
|
212
|
+
padding: 0 1rem 1rem;
|
|
141
213
|
}
|
|
142
214
|
```
|
|
143
215
|
|
|
144
|
-
|
|
216
|
+
### Tailwind Example
|
|
145
217
|
|
|
146
218
|
```html
|
|
147
|
-
<div
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
219
|
+
<div data-slot="accordion" class="overflow-hidden rounded-2xl border">
|
|
220
|
+
<div
|
|
221
|
+
data-slot="accordion-item"
|
|
222
|
+
data-value="one"
|
|
223
|
+
class="group border-b data-[open]:bg-muted/50"
|
|
224
|
+
>
|
|
225
|
+
<button
|
|
226
|
+
data-slot="accordion-trigger"
|
|
227
|
+
class="flex w-full items-center gap-6 p-4 text-left text-sm font-medium hover:underline"
|
|
228
|
+
>
|
|
229
|
+
<span>Section One</span>
|
|
230
|
+
<svg
|
|
231
|
+
data-slot="accordion-trigger-icon"
|
|
232
|
+
viewBox="0 0 12 12"
|
|
233
|
+
class="ml-auto size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-45"
|
|
234
|
+
>
|
|
235
|
+
<path d="M6.75 0H5.25V5.25H0V6.75H5.25V12H6.75V6.75H12V5.25H6.75V0Z" />
|
|
236
|
+
</svg>
|
|
237
|
+
</button>
|
|
238
|
+
<div
|
|
239
|
+
data-slot="accordion-content"
|
|
240
|
+
class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] ease-out data-[starting-style]:h-0"
|
|
241
|
+
>
|
|
242
|
+
<div data-slot="accordion-content-inner" class="px-4 pb-4 pt-0">
|
|
243
|
+
Content
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
153
247
|
</div>
|
|
154
248
|
```
|
|
155
249
|
|
|
156
250
|
## Keyboard Navigation
|
|
157
251
|
|
|
158
|
-
| Key
|
|
159
|
-
|
|
|
160
|
-
| `Enter` / `Space` | Toggle focused item
|
|
161
|
-
| `ArrowDown`
|
|
162
|
-
| `
|
|
163
|
-
| `Home`
|
|
164
|
-
| `End`
|
|
252
|
+
| Key | Action |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| `Enter` / `Space` | Toggle focused item |
|
|
255
|
+
| `ArrowDown` / `ArrowUp` | Move focus in vertical accordions |
|
|
256
|
+
| `ArrowRight` / `ArrowLeft` | Move focus in horizontal accordions |
|
|
257
|
+
| `Home` | Move focus to first enabled trigger |
|
|
258
|
+
| `End` | Move focus to last enabled trigger |
|
|
259
|
+
|
|
260
|
+
Disabled items are skipped during roving focus.
|
|
165
261
|
|
|
166
262
|
## Events
|
|
167
263
|
|
|
@@ -180,22 +276,20 @@ element.addEventListener("accordion:change", (e) => {
|
|
|
180
276
|
Control the accordion via events:
|
|
181
277
|
|
|
182
278
|
| Event | Detail | Description |
|
|
183
|
-
|
|
279
|
+
| --- | --- | --- |
|
|
184
280
|
| `accordion:set` | `{ value: string \| string[] }` | Set expanded items programmatically |
|
|
185
281
|
|
|
186
282
|
```javascript
|
|
187
|
-
// Expand a single item
|
|
188
283
|
element.dispatchEvent(
|
|
189
284
|
new CustomEvent("accordion:set", { detail: { value: "one" } })
|
|
190
285
|
);
|
|
191
286
|
|
|
192
|
-
// Expand multiple items (when data-multiple is set)
|
|
193
287
|
element.dispatchEvent(
|
|
194
288
|
new CustomEvent("accordion:set", { detail: { value: ["one", "two"] } })
|
|
195
289
|
);
|
|
196
290
|
```
|
|
197
291
|
|
|
198
|
-
|
|
292
|
+
`accordion:set` and controller methods still work when the accordion is disabled. User-triggered click and keyboard interaction do not.
|
|
199
293
|
|
|
200
294
|
## License
|
|
201
295
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@data-slot/core`);const t=`@data-slot/accordion`;function
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@data-slot/core`);const t=[`horizontal`,`vertical`],n=new Set([`all`,`height`,`width`,`block-size`,`inline-size`]),r=new Set([`Enter`,` `]),i=e=>!!e&&(e.hasAttribute(`disabled`)||e.hasAttribute(`data-disabled`)||e.getAttribute(`aria-disabled`)===`true`),a=(e,t,n)=>{n?e.setAttribute(t,``):e.removeAttribute(t)},o=(e,t)=>{e.setAttribute(`data-state`,t?`open`:`closed`),t?(e.setAttribute(`data-open`,``),e.removeAttribute(`data-closed`)):(e.setAttribute(`data-closed`,``),e.removeAttribute(`data-open`))},s=e=>{let t=e.trim();return t?t.endsWith(`ms`)?Number.parseFloat(t.slice(0,-2))||0:t.endsWith(`s`)?(Number.parseFloat(t.slice(0,-1))||0)*1e3:Number.parseFloat(t)||0:0},c=(e,t)=>{let n=e.split(`,`),r=t.split(`,`),i=Math.max(n.length,r.length),a=0;for(let e=0;e<i;e+=1){let t=s(n[e]??n[n.length-1]??`0`),i=s(r[e]??r[r.length-1]??`0`);a=Math.max(a,t+i)}return a},l=e=>{let t=getComputedStyle(e),n=c(t.transitionDuration,t.transitionDelay),r=c(t.animationDuration,t.animationDelay);return Math.max(n,r)},u=(e,t)=>{let n=getComputedStyle(e),r=n.transitionProperty.split(`,`).map(e=>e.trim()),i=n.transitionDuration.split(`,`),a=n.transitionDelay.split(`,`),o=Math.max(r.length,i.length,a.length),c=0;for(let e=0;e<o;e+=1){if(!t(r[e]??r[r.length-1]??`all`))continue;let n=s(i[e]??i[i.length-1]??`0`),o=s(a[e]??a[a.length-1]??`0`);c=Math.max(c,n+o)}return c},d=e=>u(e,e=>n.has(e)),f=`@data-slot/accordion`;function p(s,c={}){let u=(0,e.reuseRootBinding)(s,f,`[@data-slot/accordion] createAccordion() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(u)return u;let p=s,m=(0,e.getParts)(s,`accordion-item`);if(m.length===0)throw Error(`Accordion requires at least one accordion-item`);let h=s.ownerDocument?.defaultView??window,g=c.multiple??(0,e.getDataBool)(s,`multiple`)??!1,_=c.onValueChange,v=c.disabled??(0,e.getDataBool)(s,`disabled`)??i(s),y=c.orientation??(0,e.getDataEnum)(s,`orientation`,t)??`vertical`,b=c.loopFocus??(0,e.getDataBool)(s,`loopFocus`)??!0,x=c.hiddenUntilFound??(0,e.getDataBool)(s,`hiddenUntilFound`)??!1,S=c.collapsible??(0,e.getDataBool)(s,`collapsible`)??!0,C=[],w=[],T=(e,t,n)=>{e.content.style.setProperty(`--accordion-panel-height`,t),e.content.style.setProperty(`--accordion-panel-width`,n)},E=(e,t,n)=>{T(e,`${t}px`,`${n}px`)},D=e=>{T(e,`auto`,`auto`)},O=e=>{E(e,0,0)},k=e=>{E(e,e.content.scrollHeight,e.content.scrollWidth)},A=e=>{let t=e.content.style.getPropertyValue(`--accordion-panel-height`).trim(),n=e.content.style.getPropertyValue(`--accordion-panel-width`).trim();return t===`auto`&&n===`auto`},j=e=>{e.suppressClick=!1,e.suppressClickTimeoutId!==null&&(h.clearTimeout(e.suppressClickTimeoutId),e.suppressClickTimeoutId=null)},M=e=>{e.openSettleRafId!==null&&(h.cancelAnimationFrame(e.openSettleRafId),e.openSettleRafId=null),e.openSettleTimeoutId!==null&&(h.clearTimeout(e.openSettleTimeoutId),e.openSettleTimeoutId=null),e.openSettleCleanups.forEach(e=>e()),e.openSettleCleanups=[]},N=e=>{e.closeZeroRafId!==null&&(h.cancelAnimationFrame(e.closeZeroRafId),e.closeZeroRafId=null)},P=e=>{M(e),N(e)},F=e=>{e.content.removeAttribute(`hidden`)},I=e=>{x?e.content.setAttribute(`hidden`,`until-found`):e.content.hidden=!0,O(e)},L=new Set,R=e=>{M(e),!(!L.has(e.value)||e.presence.isExiting)&&D(e)},z=e=>{M(e);let t=l(e.content),r=d(e.content),i=r||t;if(i>0){let t=typeof h.performance?.now==`function`?h.performance.now():Date.now(),a=e=>(typeof h.performance?.now==`function`?h.performance.now():Date.now())-t>=Math.max(0,e-5),o=t=>{if(t.target!==e.content)return;let o=`propertyName`in t?String(t.propertyName):``;if(r>0){if(!n.has(o)||!a(r))return}else if(!a(i))return;R(e)},s=t=>{t.target===e.content&&(r>0||a(i)&&R(e))};e.content.addEventListener(`transitionend`,o),e.content.addEventListener(`animationend`,s),e.openSettleCleanups.push(()=>e.content.removeEventListener(`transitionend`,o)),e.openSettleCleanups.push(()=>e.content.removeEventListener(`animationend`,s)),e.openSettleTimeoutId=h.setTimeout(()=>{e.openSettleTimeoutId=null,R(e)},Math.ceil(i)+50);return}e.openSettleRafId=h.requestAnimationFrame(()=>{e.openSettleRafId=null,R(e)})},B=e=>{N(e),e.closeZeroRafId=h.requestAnimationFrame(()=>{e.closeZeroRafId=null,!L.has(e.value)&&e.presence.isExiting&&O(e)})},V=e=>{e.el.setAttribute(`data-index`,String(e.index)),e.content.setAttribute(`data-index`,String(e.index)),e.content.setAttribute(`data-orientation`,y),a(e.el,`data-disabled`,e.disabled),a(e.trigger,`data-disabled`,e.disabled),a(e.content,`data-disabled`,e.disabled),e.disabled?(e.trigger.setAttribute(`aria-disabled`,`true`),e.trigger instanceof HTMLButtonElement&&(e.trigger.disabled=!0)):(e.trigger.removeAttribute(`aria-disabled`),e.trigger instanceof HTMLButtonElement&&(e.trigger.disabled=!1))},H=(e,t)=>{e.trigger.setAttribute(`data-state`,t?`open`:`closed`),a(e.trigger,`data-panel-open`,t)},U=t=>{let n=L.has(t.value);V(t),(0,e.setAria)(t.trigger,`expanded`,n),o(t.el,n),o(t.content,n),H(t,n),t.content.removeAttribute(`data-starting-style`),t.content.removeAttribute(`data-ending-style`),n?(F(t),k(t),z(t)):I(t)},W=t=>{let n=L.has(t.value),r=t.trigger.getAttribute(`aria-expanded`)===`true`;if(V(t),(0,e.setAria)(t.trigger,`expanded`,n),o(t.el,n),o(t.content,n),H(t,n),n){N(t),F(t),k(t),r||t.presence.enter(),z(t);return}if(r){M(t),k(t),t.presence.exit(),B(t);return}P(t),t.content.removeAttribute(`data-starting-style`),t.content.removeAttribute(`data-ending-style`),I(t)},G=e=>{let t=[],n=new Set;for(let r of e)if(!(n.has(r)||!m.some(e=>e.dataset.value===r))&&(n.add(r),t.push(r),!g&&t.length===1))break;return t},K=e=>e.size===L.size?[...e].some(e=>!L.has(e)):!0,q=()=>{w.forEach(W)},J=()=>{let t=[...L];(0,e.emit)(s,`accordion:change`,{value:t}),_?.(t)},Y=e=>{let t=G(e);if(!g&&!S&&t.length===0&&L.size>0)return!1;let n=new Set(t);return K(n)?(L=n,q(),J(),!0):!1},X=e=>(e.getAttribute(`dir`)??p.getAttribute(`dir`))===`rtl`||(getComputedStyle(e).direction||getComputedStyle(p).direction||s.ownerDocument?.documentElement.getAttribute(`dir`)||``)===`rtl`?`rtl`:`ltr`;p.setAttribute(`data-orientation`,y),a(p,`data-disabled`,!!v),m.forEach((t,n)=>{let a=t.dataset.value;if(!a)return;let o=(0,e.getPart)(t,`accordion-trigger`),s=(0,e.getPart)(t,`accordion-content`);if(!o||!s)return;let c=(0,e.ensureId)(s,`accordion-content`),l=(0,e.ensureId)(o,`accordion-trigger`);o.setAttribute(`aria-controls`,c),s.setAttribute(`aria-labelledby`,l),s.setAttribute(`role`,`region`);let u=!!v||i(t)||i(o),d;d={el:t,value:a,index:n,disabled:u,trigger:o,content:s,presence:(0,e.createPresenceLifecycle)({element:s,onExitComplete:()=>{N(d),I(d)}}),sizeObserver:null,openSettleRafId:null,openSettleTimeoutId:null,closeZeroRafId:null,openSettleCleanups:[],suppressClick:!1,suppressClickTimeoutId:null},typeof ResizeObserver<`u`&&(d.sizeObserver=new ResizeObserver(()=>{!L.has(d.value)||d.presence.isExiting||A(d)||k(d)}),d.sizeObserver.observe(s)),C.push((0,e.on)(o,`click`,()=>{if(d.suppressClick){j(d);return}d.disabled||(L.has(d.value)?Y([...L].filter(e=>e!==d.value)):Y(g?[...L,d.value]:[d.value]))})),C.push((0,e.on)(o,`keydown`,e=>{if(r.has(e.key)){if(d.disabled){e.preventDefault();return}e.preventDefault(),j(d),d.suppressClick=!0,d.suppressClickTimeoutId=h.setTimeout(()=>{d.suppressClick=!1,d.suppressClickTimeoutId=null},0),L.has(d.value)?Y([...L].filter(e=>e!==d.value)):Y(g?[...L,d.value]:[d.value])}})),x&&C.push((0,e.on)(s,`beforematch`,()=>{Y(g?[...L,d.value]:[d.value])})),w.push(d)});let Z=new Set(w.map(e=>e.value)),Q=c.defaultValue??(0,e.getDataString)(s,`defaultValue`),ee=G((Q?Array.isArray(Q)?Q:[Q]:[]).filter(e=>Z.has(e)));L=new Set(ee),w.forEach(U),C.push((0,e.on)(p,`keydown`,e=>{let t=e.target;if(!t)return;let n=w.find(e=>e.trigger===t);if(!n)return;let r=w.filter(e=>!e.disabled),i=r.findIndex(e=>e.trigger===t);if(i===-1)return;let a=r.length-1,o=-1,s=()=>{o=b?i+1>a?0:i+1:Math.min(i+1,a)},c=()=>{o=b?i===0?a:i-1:Math.max(i-1,0)};switch(e.key){case`ArrowDown`:y===`vertical`&&s();break;case`ArrowUp`:y===`vertical`&&c();break;case`ArrowRight`:y===`horizontal`&&(X(n.trigger)===`rtl`?c():s());break;case`ArrowLeft`:y===`horizontal`&&(X(n.trigger)===`rtl`?s():c());break;case`Home`:o=0;break;case`End`:o=a;break;default:return}o<0||(e.preventDefault(),r[o]?.trigger.focus())})),C.push((0,e.on)(s,`accordion:set`,e=>{let t=e.detail?.value;t!==void 0&&Y(Array.isArray(t)?t:[t])}));let $={expand:e=>{!Z.has(e)||L.has(e)||Y(g?[...L,e]:[e])},collapse:e=>{!Z.has(e)||!L.has(e)||Y([...L].filter(t=>t!==e))},toggle:e=>{Z.has(e)&&(L.has(e)?$.collapse(e):$.expand(e))},get value(){return[...L]},destroy:()=>{w.forEach(e=>{j(e),e.presence.cleanup(),P(e),e.sizeObserver?.disconnect(),e.sizeObserver=null}),C.forEach(e=>e()),C.length=0,(0,e.clearRootBinding)(s,f,$)}};return(0,e.setRootBinding)(s,f,$),$}function m(t=document){let n=[];for(let r of(0,e.getRoots)(t,`accordion`))(0,e.hasRootBinding)(r,f)||n.push(p(r));return n}exports.create=m,exports.createAccordion=p;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
//#region src/index.d.ts
|
|
2
|
+
declare const ORIENTATIONS: readonly ["horizontal", "vertical"];
|
|
3
|
+
type AccordionOrientation = (typeof ORIENTATIONS)[number];
|
|
2
4
|
interface AccordionOptions {
|
|
3
5
|
/** Allow multiple items open at once */
|
|
4
6
|
multiple?: boolean;
|
|
@@ -6,7 +8,18 @@ interface AccordionOptions {
|
|
|
6
8
|
defaultValue?: string | string[];
|
|
7
9
|
/** Callback when expanded items change */
|
|
8
10
|
onValueChange?: (value: string[]) => void;
|
|
9
|
-
/**
|
|
11
|
+
/** Disable the entire accordion */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Accordion orientation for roving focus */
|
|
14
|
+
orientation?: AccordionOrientation;
|
|
15
|
+
/** Whether arrow-key focus wraps at the ends */
|
|
16
|
+
loopFocus?: boolean;
|
|
17
|
+
/** Use hidden="until-found" on closed panels */
|
|
18
|
+
hiddenUntilFound?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated Use the Base UI-style default collapsible behavior instead.
|
|
21
|
+
* Kept for backward compatibility and planned for removal in the next major.
|
|
22
|
+
*/
|
|
10
23
|
collapsible?: boolean;
|
|
11
24
|
}
|
|
12
25
|
interface AccordionController {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
//#region src/index.d.ts
|
|
2
|
+
declare const ORIENTATIONS: readonly ["horizontal", "vertical"];
|
|
3
|
+
type AccordionOrientation = (typeof ORIENTATIONS)[number];
|
|
2
4
|
interface AccordionOptions {
|
|
3
5
|
/** Allow multiple items open at once */
|
|
4
6
|
multiple?: boolean;
|
|
@@ -6,7 +8,18 @@ interface AccordionOptions {
|
|
|
6
8
|
defaultValue?: string | string[];
|
|
7
9
|
/** Callback when expanded items change */
|
|
8
10
|
onValueChange?: (value: string[]) => void;
|
|
9
|
-
/**
|
|
11
|
+
/** Disable the entire accordion */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Accordion orientation for roving focus */
|
|
14
|
+
orientation?: AccordionOrientation;
|
|
15
|
+
/** Whether arrow-key focus wraps at the ends */
|
|
16
|
+
loopFocus?: boolean;
|
|
17
|
+
/** Use hidden="until-found" on closed panels */
|
|
18
|
+
hiddenUntilFound?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated Use the Base UI-style default collapsible behavior instead.
|
|
21
|
+
* Kept for backward compatibility and planned for removal in the next major.
|
|
22
|
+
*/
|
|
10
23
|
collapsible?: boolean;
|
|
11
24
|
}
|
|
12
25
|
interface AccordionController {
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{clearRootBinding as e,
|
|
1
|
+
import{clearRootBinding as e,createPresenceLifecycle as t,emit as n,ensureId as r,getDataBool as i,getDataEnum as a,getDataString as o,getPart as s,getParts as c,getRoots as l,hasRootBinding as u,on as d,reuseRootBinding as f,setAria as p,setRootBinding as m}from"@data-slot/core";const ee=[`horizontal`,`vertical`],h=new Set([`all`,`height`,`width`,`block-size`,`inline-size`]),te=new Set([`Enter`,` `]),g=e=>!!e&&(e.hasAttribute(`disabled`)||e.hasAttribute(`data-disabled`)||e.getAttribute(`aria-disabled`)===`true`),_=(e,t,n)=>{n?e.setAttribute(t,``):e.removeAttribute(t)},v=(e,t)=>{e.setAttribute(`data-state`,t?`open`:`closed`),t?(e.setAttribute(`data-open`,``),e.removeAttribute(`data-closed`)):(e.setAttribute(`data-closed`,``),e.removeAttribute(`data-open`))},y=e=>{let t=e.trim();return t?t.endsWith(`ms`)?Number.parseFloat(t.slice(0,-2))||0:t.endsWith(`s`)?(Number.parseFloat(t.slice(0,-1))||0)*1e3:Number.parseFloat(t)||0:0},b=(e,t)=>{let n=e.split(`,`),r=t.split(`,`),i=Math.max(n.length,r.length),a=0;for(let e=0;e<i;e+=1){let t=y(n[e]??n[n.length-1]??`0`),i=y(r[e]??r[r.length-1]??`0`);a=Math.max(a,t+i)}return a},ne=e=>{let t=getComputedStyle(e),n=b(t.transitionDuration,t.transitionDelay),r=b(t.animationDuration,t.animationDelay);return Math.max(n,r)},x=(e,t)=>{let n=getComputedStyle(e),r=n.transitionProperty.split(`,`).map(e=>e.trim()),i=n.transitionDuration.split(`,`),a=n.transitionDelay.split(`,`),o=Math.max(r.length,i.length,a.length),s=0;for(let e=0;e<o;e+=1){if(!t(r[e]??r[r.length-1]??`all`))continue;let n=y(i[e]??i[i.length-1]??`0`),o=y(a[e]??a[a.length-1]??`0`);s=Math.max(s,n+o)}return s},re=e=>x(e,e=>h.has(e)),S=`@data-slot/accordion`;function C(l,u={}){let y=f(l,S,`[@data-slot/accordion] createAccordion() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(y)return y;let b=l,x=c(l,`accordion-item`);if(x.length===0)throw Error(`Accordion requires at least one accordion-item`);let C=l.ownerDocument?.defaultView??window,w=u.multiple??i(l,`multiple`)??!1,ie=u.onValueChange,T=u.disabled??i(l,`disabled`)??g(l),E=u.orientation??a(l,`orientation`,ee)??`vertical`,D=u.loopFocus??i(l,`loopFocus`)??!0,O=u.hiddenUntilFound??i(l,`hiddenUntilFound`)??!1,ae=u.collapsible??i(l,`collapsible`)??!0,k=[],A=[],j=(e,t,n)=>{e.content.style.setProperty(`--accordion-panel-height`,t),e.content.style.setProperty(`--accordion-panel-width`,n)},M=(e,t,n)=>{j(e,`${t}px`,`${n}px`)},N=e=>{j(e,`auto`,`auto`)},P=e=>{M(e,0,0)},F=e=>{M(e,e.content.scrollHeight,e.content.scrollWidth)},I=e=>{let t=e.content.style.getPropertyValue(`--accordion-panel-height`).trim(),n=e.content.style.getPropertyValue(`--accordion-panel-width`).trim();return t===`auto`&&n===`auto`},L=e=>{e.suppressClick=!1,e.suppressClickTimeoutId!==null&&(C.clearTimeout(e.suppressClickTimeoutId),e.suppressClickTimeoutId=null)},R=e=>{e.openSettleRafId!==null&&(C.cancelAnimationFrame(e.openSettleRafId),e.openSettleRafId=null),e.openSettleTimeoutId!==null&&(C.clearTimeout(e.openSettleTimeoutId),e.openSettleTimeoutId=null),e.openSettleCleanups.forEach(e=>e()),e.openSettleCleanups=[]},z=e=>{e.closeZeroRafId!==null&&(C.cancelAnimationFrame(e.closeZeroRafId),e.closeZeroRafId=null)},B=e=>{R(e),z(e)},V=e=>{e.content.removeAttribute(`hidden`)},H=e=>{O?e.content.setAttribute(`hidden`,`until-found`):e.content.hidden=!0,P(e)},U=new Set,W=e=>{R(e),!(!U.has(e.value)||e.presence.isExiting)&&N(e)},G=e=>{R(e);let t=ne(e.content),n=re(e.content),r=n||t;if(r>0){let t=typeof C.performance?.now==`function`?C.performance.now():Date.now(),i=e=>(typeof C.performance?.now==`function`?C.performance.now():Date.now())-t>=Math.max(0,e-5),a=t=>{if(t.target!==e.content)return;let a=`propertyName`in t?String(t.propertyName):``;if(n>0){if(!h.has(a)||!i(n))return}else if(!i(r))return;W(e)},o=t=>{t.target===e.content&&(n>0||i(r)&&W(e))};e.content.addEventListener(`transitionend`,a),e.content.addEventListener(`animationend`,o),e.openSettleCleanups.push(()=>e.content.removeEventListener(`transitionend`,a)),e.openSettleCleanups.push(()=>e.content.removeEventListener(`animationend`,o)),e.openSettleTimeoutId=C.setTimeout(()=>{e.openSettleTimeoutId=null,W(e)},Math.ceil(r)+50);return}e.openSettleRafId=C.requestAnimationFrame(()=>{e.openSettleRafId=null,W(e)})},oe=e=>{z(e),e.closeZeroRafId=C.requestAnimationFrame(()=>{e.closeZeroRafId=null,!U.has(e.value)&&e.presence.isExiting&&P(e)})},K=e=>{e.el.setAttribute(`data-index`,String(e.index)),e.content.setAttribute(`data-index`,String(e.index)),e.content.setAttribute(`data-orientation`,E),_(e.el,`data-disabled`,e.disabled),_(e.trigger,`data-disabled`,e.disabled),_(e.content,`data-disabled`,e.disabled),e.disabled?(e.trigger.setAttribute(`aria-disabled`,`true`),e.trigger instanceof HTMLButtonElement&&(e.trigger.disabled=!0)):(e.trigger.removeAttribute(`aria-disabled`),e.trigger instanceof HTMLButtonElement&&(e.trigger.disabled=!1))},q=(e,t)=>{e.trigger.setAttribute(`data-state`,t?`open`:`closed`),_(e.trigger,`data-panel-open`,t)},se=e=>{let t=U.has(e.value);K(e),p(e.trigger,`expanded`,t),v(e.el,t),v(e.content,t),q(e,t),e.content.removeAttribute(`data-starting-style`),e.content.removeAttribute(`data-ending-style`),t?(V(e),F(e),G(e)):H(e)},ce=e=>{let t=U.has(e.value),n=e.trigger.getAttribute(`aria-expanded`)===`true`;if(K(e),p(e.trigger,`expanded`,t),v(e.el,t),v(e.content,t),q(e,t),t){z(e),V(e),F(e),n||e.presence.enter(),G(e);return}if(n){R(e),F(e),e.presence.exit(),oe(e);return}B(e),e.content.removeAttribute(`data-starting-style`),e.content.removeAttribute(`data-ending-style`),H(e)},J=e=>{let t=[],n=new Set;for(let r of e)if(!(n.has(r)||!x.some(e=>e.dataset.value===r))&&(n.add(r),t.push(r),!w&&t.length===1))break;return t},le=e=>e.size===U.size?[...e].some(e=>!U.has(e)):!0,ue=()=>{A.forEach(ce)},de=()=>{let e=[...U];n(l,`accordion:change`,{value:e}),ie?.(e)},Y=e=>{let t=J(e);if(!w&&!ae&&t.length===0&&U.size>0)return!1;let n=new Set(t);return le(n)?(U=n,ue(),de(),!0):!1},X=e=>(e.getAttribute(`dir`)??b.getAttribute(`dir`))===`rtl`||(getComputedStyle(e).direction||getComputedStyle(b).direction||l.ownerDocument?.documentElement.getAttribute(`dir`)||``)===`rtl`?`rtl`:`ltr`;b.setAttribute(`data-orientation`,E),_(b,`data-disabled`,!!T),x.forEach((e,n)=>{let i=e.dataset.value;if(!i)return;let a=s(e,`accordion-trigger`),o=s(e,`accordion-content`);if(!a||!o)return;let c=r(o,`accordion-content`),l=r(a,`accordion-trigger`);a.setAttribute(`aria-controls`,c),o.setAttribute(`aria-labelledby`,l),o.setAttribute(`role`,`region`);let u=!!T||g(e)||g(a),f;f={el:e,value:i,index:n,disabled:u,trigger:a,content:o,presence:t({element:o,onExitComplete:()=>{z(f),H(f)}}),sizeObserver:null,openSettleRafId:null,openSettleTimeoutId:null,closeZeroRafId:null,openSettleCleanups:[],suppressClick:!1,suppressClickTimeoutId:null},typeof ResizeObserver<`u`&&(f.sizeObserver=new ResizeObserver(()=>{!U.has(f.value)||f.presence.isExiting||I(f)||F(f)}),f.sizeObserver.observe(o)),k.push(d(a,`click`,()=>{if(f.suppressClick){L(f);return}f.disabled||(U.has(f.value)?Y([...U].filter(e=>e!==f.value)):Y(w?[...U,f.value]:[f.value]))})),k.push(d(a,`keydown`,e=>{if(te.has(e.key)){if(f.disabled){e.preventDefault();return}e.preventDefault(),L(f),f.suppressClick=!0,f.suppressClickTimeoutId=C.setTimeout(()=>{f.suppressClick=!1,f.suppressClickTimeoutId=null},0),U.has(f.value)?Y([...U].filter(e=>e!==f.value)):Y(w?[...U,f.value]:[f.value])}})),O&&k.push(d(o,`beforematch`,()=>{Y(w?[...U,f.value]:[f.value])})),A.push(f)});let Z=new Set(A.map(e=>e.value)),Q=u.defaultValue??o(l,`defaultValue`),fe=J((Q?Array.isArray(Q)?Q:[Q]:[]).filter(e=>Z.has(e)));U=new Set(fe),A.forEach(se),k.push(d(b,`keydown`,e=>{let t=e.target;if(!t)return;let n=A.find(e=>e.trigger===t);if(!n)return;let r=A.filter(e=>!e.disabled),i=r.findIndex(e=>e.trigger===t);if(i===-1)return;let a=r.length-1,o=-1,s=()=>{o=D?i+1>a?0:i+1:Math.min(i+1,a)},c=()=>{o=D?i===0?a:i-1:Math.max(i-1,0)};switch(e.key){case`ArrowDown`:E===`vertical`&&s();break;case`ArrowUp`:E===`vertical`&&c();break;case`ArrowRight`:E===`horizontal`&&(X(n.trigger)===`rtl`?c():s());break;case`ArrowLeft`:E===`horizontal`&&(X(n.trigger)===`rtl`?s():c());break;case`Home`:o=0;break;case`End`:o=a;break;default:return}o<0||(e.preventDefault(),r[o]?.trigger.focus())})),k.push(d(l,`accordion:set`,e=>{let t=e.detail?.value;t!==void 0&&Y(Array.isArray(t)?t:[t])}));let $={expand:e=>{!Z.has(e)||U.has(e)||Y(w?[...U,e]:[e])},collapse:e=>{!Z.has(e)||!U.has(e)||Y([...U].filter(t=>t!==e))},toggle:e=>{Z.has(e)&&(U.has(e)?$.collapse(e):$.expand(e))},get value(){return[...U]},destroy:()=>{A.forEach(e=>{L(e),e.presence.cleanup(),B(e),e.sizeObserver?.disconnect(),e.sizeObserver=null}),k.forEach(e=>e()),k.length=0,e(l,S,$)}};return m(l,S,$),$}function w(e=document){let t=[];for(let n of l(e,`accordion`))u(n,S)||t.push(C(n));return t}export{w as create,C as createAccordion};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@data-slot/accordion",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.151",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
],
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@data-slot/core": "0.2.
|
|
37
|
+
"@data-slot/core": "0.2.151"
|
|
38
38
|
}
|
|
39
39
|
}
|