concertina 0.4.0 → 0.5.0

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/dist/index.cjs CHANGED
@@ -32,27 +32,988 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ConcertinaContext: () => ConcertinaContext,
34
34
  ConcertinaStore: () => ConcertinaStore,
35
- Content: () => Content2,
36
- Header: () => import_react_accordion.Header,
35
+ Content: () => Content3,
36
+ Header: () => Header,
37
37
  Item: () => Item2,
38
- Root: () => Root2,
39
- Trigger: () => import_react_accordion.Trigger,
38
+ Root: () => Root3,
39
+ Slot: () => Slot,
40
+ StableSlot: () => StableSlot,
41
+ Trigger: () => Trigger2,
40
42
  pinToScrollTop: () => pinToScrollTop,
41
43
  useConcertina: () => useConcertina,
42
- useExpanded: () => useExpanded
44
+ useExpanded: () => useExpanded,
45
+ useStableSlot: () => useStableSlot,
46
+ useTransitionLock: () => useTransitionLock
43
47
  });
44
48
  module.exports = __toCommonJS(index_exports);
45
49
 
46
50
  // src/root.tsx
47
- var import_react2 = require("react");
48
- var Accordion = __toESM(require("@radix-ui/react-accordion"), 1);
51
+ var import_react6 = require("react");
52
+
53
+ // node_modules/@radix-ui/react-accordion/dist/index.mjs
54
+ var import_react3 = __toESM(require("react"), 1);
55
+
56
+ // node_modules/@radix-ui/react-context/dist/index.mjs
57
+ var React = __toESM(require("react"), 1);
58
+ var import_jsx_runtime = require("react/jsx-runtime");
59
+ function createContextScope(scopeName, createContextScopeDeps = []) {
60
+ let defaultContexts = [];
61
+ function createContext32(rootComponentName, defaultContext) {
62
+ const BaseContext = React.createContext(defaultContext);
63
+ const index = defaultContexts.length;
64
+ defaultContexts = [...defaultContexts, defaultContext];
65
+ const Provider = (props) => {
66
+ const { scope, children, ...context } = props;
67
+ const Context = scope?.[scopeName]?.[index] || BaseContext;
68
+ const value = React.useMemo(() => context, Object.values(context));
69
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Context.Provider, { value, children });
70
+ };
71
+ Provider.displayName = rootComponentName + "Provider";
72
+ function useContext22(consumerName, scope) {
73
+ const Context = scope?.[scopeName]?.[index] || BaseContext;
74
+ const context = React.useContext(Context);
75
+ if (context) return context;
76
+ if (defaultContext !== void 0) return defaultContext;
77
+ throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
78
+ }
79
+ return [Provider, useContext22];
80
+ }
81
+ const createScope = () => {
82
+ const scopeContexts = defaultContexts.map((defaultContext) => {
83
+ return React.createContext(defaultContext);
84
+ });
85
+ return function useScope(scope) {
86
+ const contexts = scope?.[scopeName] || scopeContexts;
87
+ return React.useMemo(
88
+ () => ({ [`__scope${scopeName}`]: { ...scope, [scopeName]: contexts } }),
89
+ [scope, contexts]
90
+ );
91
+ };
92
+ };
93
+ createScope.scopeName = scopeName;
94
+ return [createContext32, composeContextScopes(createScope, ...createContextScopeDeps)];
95
+ }
96
+ function composeContextScopes(...scopes) {
97
+ const baseScope = scopes[0];
98
+ if (scopes.length === 1) return baseScope;
99
+ const createScope = () => {
100
+ const scopeHooks = scopes.map((createScope2) => ({
101
+ useScope: createScope2(),
102
+ scopeName: createScope2.scopeName
103
+ }));
104
+ return function useComposedScopes(overrideScopes) {
105
+ const nextScopes = scopeHooks.reduce((nextScopes2, { useScope, scopeName }) => {
106
+ const scopeProps = useScope(overrideScopes);
107
+ const currentScope = scopeProps[`__scope${scopeName}`];
108
+ return { ...nextScopes2, ...currentScope };
109
+ }, {});
110
+ return React.useMemo(() => ({ [`__scope${baseScope.scopeName}`]: nextScopes }), [nextScopes]);
111
+ };
112
+ };
113
+ createScope.scopeName = baseScope.scopeName;
114
+ return createScope;
115
+ }
116
+
117
+ // node_modules/@radix-ui/react-collection/dist/index.mjs
118
+ var import_react = __toESM(require("react"), 1);
119
+
120
+ // node_modules/@radix-ui/react-compose-refs/dist/index.mjs
121
+ var React2 = __toESM(require("react"), 1);
122
+ function setRef(ref, value) {
123
+ if (typeof ref === "function") {
124
+ return ref(value);
125
+ } else if (ref !== null && ref !== void 0) {
126
+ ref.current = value;
127
+ }
128
+ }
129
+ function composeRefs(...refs) {
130
+ return (node) => {
131
+ let hasCleanup = false;
132
+ const cleanups = refs.map((ref) => {
133
+ const cleanup = setRef(ref, node);
134
+ if (!hasCleanup && typeof cleanup == "function") {
135
+ hasCleanup = true;
136
+ }
137
+ return cleanup;
138
+ });
139
+ if (hasCleanup) {
140
+ return () => {
141
+ for (let i = 0; i < cleanups.length; i++) {
142
+ const cleanup = cleanups[i];
143
+ if (typeof cleanup == "function") {
144
+ cleanup();
145
+ } else {
146
+ setRef(refs[i], null);
147
+ }
148
+ }
149
+ };
150
+ }
151
+ };
152
+ }
153
+ function useComposedRefs(...refs) {
154
+ return React2.useCallback(composeRefs(...refs), refs);
155
+ }
156
+
157
+ // node_modules/@radix-ui/react-slot/dist/index.mjs
158
+ var React3 = __toESM(require("react"), 1);
159
+ var import_jsx_runtime2 = require("react/jsx-runtime");
160
+ // @__NO_SIDE_EFFECTS__
161
+ function createSlot(ownerName) {
162
+ const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
163
+ const Slot22 = React3.forwardRef((props, forwardedRef) => {
164
+ const { children, ...slotProps } = props;
165
+ const childrenArray = React3.Children.toArray(children);
166
+ const slottable = childrenArray.find(isSlottable);
167
+ if (slottable) {
168
+ const newElement = slottable.props.children;
169
+ const newChildren = childrenArray.map((child) => {
170
+ if (child === slottable) {
171
+ if (React3.Children.count(newElement) > 1) return React3.Children.only(null);
172
+ return React3.isValidElement(newElement) ? newElement.props.children : null;
173
+ } else {
174
+ return child;
175
+ }
176
+ });
177
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SlotClone, { ...slotProps, ref: forwardedRef, children: React3.isValidElement(newElement) ? React3.cloneElement(newElement, void 0, newChildren) : null });
178
+ }
179
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SlotClone, { ...slotProps, ref: forwardedRef, children });
180
+ });
181
+ Slot22.displayName = `${ownerName}.Slot`;
182
+ return Slot22;
183
+ }
184
+ // @__NO_SIDE_EFFECTS__
185
+ function createSlotClone(ownerName) {
186
+ const SlotClone = React3.forwardRef((props, forwardedRef) => {
187
+ const { children, ...slotProps } = props;
188
+ if (React3.isValidElement(children)) {
189
+ const childrenRef = getElementRef(children);
190
+ const props2 = mergeProps(slotProps, children.props);
191
+ if (children.type !== React3.Fragment) {
192
+ props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
193
+ }
194
+ return React3.cloneElement(children, props2);
195
+ }
196
+ return React3.Children.count(children) > 1 ? React3.Children.only(null) : null;
197
+ });
198
+ SlotClone.displayName = `${ownerName}.SlotClone`;
199
+ return SlotClone;
200
+ }
201
+ var SLOTTABLE_IDENTIFIER = /* @__PURE__ */ Symbol("radix.slottable");
202
+ function isSlottable(child) {
203
+ return React3.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
204
+ }
205
+ function mergeProps(slotProps, childProps) {
206
+ const overrideProps = { ...childProps };
207
+ for (const propName in childProps) {
208
+ const slotPropValue = slotProps[propName];
209
+ const childPropValue = childProps[propName];
210
+ const isHandler = /^on[A-Z]/.test(propName);
211
+ if (isHandler) {
212
+ if (slotPropValue && childPropValue) {
213
+ overrideProps[propName] = (...args) => {
214
+ const result = childPropValue(...args);
215
+ slotPropValue(...args);
216
+ return result;
217
+ };
218
+ } else if (slotPropValue) {
219
+ overrideProps[propName] = slotPropValue;
220
+ }
221
+ } else if (propName === "style") {
222
+ overrideProps[propName] = { ...slotPropValue, ...childPropValue };
223
+ } else if (propName === "className") {
224
+ overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
225
+ }
226
+ }
227
+ return { ...slotProps, ...overrideProps };
228
+ }
229
+ function getElementRef(element) {
230
+ let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
231
+ let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
232
+ if (mayWarn) {
233
+ return element.ref;
234
+ }
235
+ getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
236
+ mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
237
+ if (mayWarn) {
238
+ return element.props.ref;
239
+ }
240
+ return element.props.ref || element.ref;
241
+ }
242
+
243
+ // node_modules/@radix-ui/react-collection/dist/index.mjs
244
+ var import_jsx_runtime3 = require("react/jsx-runtime");
245
+ var import_react2 = __toESM(require("react"), 1);
246
+ var import_jsx_runtime4 = require("react/jsx-runtime");
247
+ function createCollection(name) {
248
+ const PROVIDER_NAME = name + "CollectionProvider";
249
+ const [createCollectionContext, createCollectionScope2] = createContextScope(PROVIDER_NAME);
250
+ const [CollectionProviderImpl, useCollectionContext] = createCollectionContext(
251
+ PROVIDER_NAME,
252
+ { collectionRef: { current: null }, itemMap: /* @__PURE__ */ new Map() }
253
+ );
254
+ const CollectionProvider = (props) => {
255
+ const { scope, children } = props;
256
+ const ref = import_react.default.useRef(null);
257
+ const itemMap = import_react.default.useRef(/* @__PURE__ */ new Map()).current;
258
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
259
+ };
260
+ CollectionProvider.displayName = PROVIDER_NAME;
261
+ const COLLECTION_SLOT_NAME = name + "CollectionSlot";
262
+ const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
263
+ const CollectionSlot = import_react.default.forwardRef(
264
+ (props, forwardedRef) => {
265
+ const { scope, children } = props;
266
+ const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
267
+ const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
268
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CollectionSlotImpl, { ref: composedRefs, children });
269
+ }
270
+ );
271
+ CollectionSlot.displayName = COLLECTION_SLOT_NAME;
272
+ const ITEM_SLOT_NAME = name + "CollectionItemSlot";
273
+ const ITEM_DATA_ATTR = "data-radix-collection-item";
274
+ const CollectionItemSlotImpl = createSlot(ITEM_SLOT_NAME);
275
+ const CollectionItemSlot = import_react.default.forwardRef(
276
+ (props, forwardedRef) => {
277
+ const { scope, children, ...itemData } = props;
278
+ const ref = import_react.default.useRef(null);
279
+ const composedRefs = useComposedRefs(forwardedRef, ref);
280
+ const context = useCollectionContext(ITEM_SLOT_NAME, scope);
281
+ import_react.default.useEffect(() => {
282
+ context.itemMap.set(ref, { ref, ...itemData });
283
+ return () => void context.itemMap.delete(ref);
284
+ });
285
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
286
+ }
287
+ );
288
+ CollectionItemSlot.displayName = ITEM_SLOT_NAME;
289
+ function useCollection2(scope) {
290
+ const context = useCollectionContext(name + "CollectionConsumer", scope);
291
+ const getItems = import_react.default.useCallback(() => {
292
+ const collectionNode = context.collectionRef.current;
293
+ if (!collectionNode) return [];
294
+ const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
295
+ const items = Array.from(context.itemMap.values());
296
+ const orderedItems = items.sort(
297
+ (a, b) => orderedNodes.indexOf(a.ref.current) - orderedNodes.indexOf(b.ref.current)
298
+ );
299
+ return orderedItems;
300
+ }, [context.collectionRef, context.itemMap]);
301
+ return getItems;
302
+ }
303
+ return [
304
+ { Provider: CollectionProvider, Slot: CollectionSlot, ItemSlot: CollectionItemSlot },
305
+ useCollection2,
306
+ createCollectionScope2
307
+ ];
308
+ }
309
+
310
+ // node_modules/@radix-ui/primitive/dist/index.mjs
311
+ var canUseDOM = !!(typeof window !== "undefined" && window.document && window.document.createElement);
312
+ function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
313
+ return function handleEvent(event) {
314
+ originalEventHandler?.(event);
315
+ if (checkForDefaultPrevented === false || !event.defaultPrevented) {
316
+ return ourEventHandler?.(event);
317
+ }
318
+ };
319
+ }
320
+
321
+ // node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
322
+ var React6 = __toESM(require("react"), 1);
323
+
324
+ // node_modules/@radix-ui/react-use-layout-effect/dist/index.mjs
325
+ var React5 = __toESM(require("react"), 1);
326
+ var useLayoutEffect2 = globalThis?.document ? React5.useLayoutEffect : () => {
327
+ };
328
+
329
+ // node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
330
+ var React23 = __toESM(require("react"), 1);
331
+ var useInsertionEffect = React6[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
332
+ function useControllableState({
333
+ prop,
334
+ defaultProp,
335
+ onChange = () => {
336
+ },
337
+ caller
338
+ }) {
339
+ const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
340
+ defaultProp,
341
+ onChange
342
+ });
343
+ const isControlled = prop !== void 0;
344
+ const value = isControlled ? prop : uncontrolledProp;
345
+ if (true) {
346
+ const isControlledRef = React6.useRef(prop !== void 0);
347
+ React6.useEffect(() => {
348
+ const wasControlled = isControlledRef.current;
349
+ if (wasControlled !== isControlled) {
350
+ const from = wasControlled ? "controlled" : "uncontrolled";
351
+ const to = isControlled ? "controlled" : "uncontrolled";
352
+ console.warn(
353
+ `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`
354
+ );
355
+ }
356
+ isControlledRef.current = isControlled;
357
+ }, [isControlled, caller]);
358
+ }
359
+ const setValue = React6.useCallback(
360
+ (nextValue) => {
361
+ if (isControlled) {
362
+ const value2 = isFunction(nextValue) ? nextValue(prop) : nextValue;
363
+ if (value2 !== prop) {
364
+ onChangeRef.current?.(value2);
365
+ }
366
+ } else {
367
+ setUncontrolledProp(nextValue);
368
+ }
369
+ },
370
+ [isControlled, prop, setUncontrolledProp, onChangeRef]
371
+ );
372
+ return [value, setValue];
373
+ }
374
+ function useUncontrolledState({
375
+ defaultProp,
376
+ onChange
377
+ }) {
378
+ const [value, setValue] = React6.useState(defaultProp);
379
+ const prevValueRef = React6.useRef(value);
380
+ const onChangeRef = React6.useRef(onChange);
381
+ useInsertionEffect(() => {
382
+ onChangeRef.current = onChange;
383
+ }, [onChange]);
384
+ React6.useEffect(() => {
385
+ if (prevValueRef.current !== value) {
386
+ onChangeRef.current?.(value);
387
+ prevValueRef.current = value;
388
+ }
389
+ }, [value, prevValueRef]);
390
+ return [value, setValue, onChangeRef];
391
+ }
392
+ function isFunction(value) {
393
+ return typeof value === "function";
394
+ }
395
+
396
+ // node_modules/@radix-ui/react-primitive/dist/index.mjs
397
+ var React7 = __toESM(require("react"), 1);
398
+ var ReactDOM = __toESM(require("react-dom"), 1);
399
+ var import_jsx_runtime5 = require("react/jsx-runtime");
400
+ var NODES = [
401
+ "a",
402
+ "button",
403
+ "div",
404
+ "form",
405
+ "h2",
406
+ "h3",
407
+ "img",
408
+ "input",
409
+ "label",
410
+ "li",
411
+ "nav",
412
+ "ol",
413
+ "p",
414
+ "select",
415
+ "span",
416
+ "svg",
417
+ "ul"
418
+ ];
419
+ var Primitive = NODES.reduce((primitive, node) => {
420
+ const Slot3 = createSlot(`Primitive.${node}`);
421
+ const Node2 = React7.forwardRef((props, forwardedRef) => {
422
+ const { asChild, ...primitiveProps } = props;
423
+ const Comp = asChild ? Slot3 : node;
424
+ if (typeof window !== "undefined") {
425
+ window[/* @__PURE__ */ Symbol.for("radix-ui")] = true;
426
+ }
427
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Comp, { ...primitiveProps, ref: forwardedRef });
428
+ });
429
+ Node2.displayName = `Primitive.${node}`;
430
+ return { ...primitive, [node]: Node2 };
431
+ }, {});
432
+
433
+ // node_modules/@radix-ui/react-collapsible/dist/index.mjs
434
+ var React10 = __toESM(require("react"), 1);
435
+
436
+ // node_modules/@radix-ui/react-presence/dist/index.mjs
437
+ var React24 = __toESM(require("react"), 1);
438
+ var React8 = __toESM(require("react"), 1);
439
+ function useStateMachine(initialState, machine) {
440
+ return React8.useReducer((state, event) => {
441
+ const nextState = machine[state][event];
442
+ return nextState ?? state;
443
+ }, initialState);
444
+ }
445
+ var Presence = (props) => {
446
+ const { present, children } = props;
447
+ const presence = usePresence(present);
448
+ const child = typeof children === "function" ? children({ present: presence.isPresent }) : React24.Children.only(children);
449
+ const ref = useComposedRefs(presence.ref, getElementRef2(child));
450
+ const forceMount = typeof children === "function";
451
+ return forceMount || presence.isPresent ? React24.cloneElement(child, { ref }) : null;
452
+ };
453
+ Presence.displayName = "Presence";
454
+ function usePresence(present) {
455
+ const [node, setNode] = React24.useState();
456
+ const stylesRef = React24.useRef(null);
457
+ const prevPresentRef = React24.useRef(present);
458
+ const prevAnimationNameRef = React24.useRef("none");
459
+ const initialState = present ? "mounted" : "unmounted";
460
+ const [state, send] = useStateMachine(initialState, {
461
+ mounted: {
462
+ UNMOUNT: "unmounted",
463
+ ANIMATION_OUT: "unmountSuspended"
464
+ },
465
+ unmountSuspended: {
466
+ MOUNT: "mounted",
467
+ ANIMATION_END: "unmounted"
468
+ },
469
+ unmounted: {
470
+ MOUNT: "mounted"
471
+ }
472
+ });
473
+ React24.useEffect(() => {
474
+ const currentAnimationName = getAnimationName(stylesRef.current);
475
+ prevAnimationNameRef.current = state === "mounted" ? currentAnimationName : "none";
476
+ }, [state]);
477
+ useLayoutEffect2(() => {
478
+ const styles = stylesRef.current;
479
+ const wasPresent = prevPresentRef.current;
480
+ const hasPresentChanged = wasPresent !== present;
481
+ if (hasPresentChanged) {
482
+ const prevAnimationName = prevAnimationNameRef.current;
483
+ const currentAnimationName = getAnimationName(styles);
484
+ if (present) {
485
+ send("MOUNT");
486
+ } else if (currentAnimationName === "none" || styles?.display === "none") {
487
+ send("UNMOUNT");
488
+ } else {
489
+ const isAnimating = prevAnimationName !== currentAnimationName;
490
+ if (wasPresent && isAnimating) {
491
+ send("ANIMATION_OUT");
492
+ } else {
493
+ send("UNMOUNT");
494
+ }
495
+ }
496
+ prevPresentRef.current = present;
497
+ }
498
+ }, [present, send]);
499
+ useLayoutEffect2(() => {
500
+ if (node) {
501
+ let timeoutId;
502
+ const ownerWindow = node.ownerDocument.defaultView ?? window;
503
+ const handleAnimationEnd = (event) => {
504
+ const currentAnimationName = getAnimationName(stylesRef.current);
505
+ const isCurrentAnimation = currentAnimationName.includes(CSS.escape(event.animationName));
506
+ if (event.target === node && isCurrentAnimation) {
507
+ send("ANIMATION_END");
508
+ if (!prevPresentRef.current) {
509
+ const currentFillMode = node.style.animationFillMode;
510
+ node.style.animationFillMode = "forwards";
511
+ timeoutId = ownerWindow.setTimeout(() => {
512
+ if (node.style.animationFillMode === "forwards") {
513
+ node.style.animationFillMode = currentFillMode;
514
+ }
515
+ });
516
+ }
517
+ }
518
+ };
519
+ const handleAnimationStart = (event) => {
520
+ if (event.target === node) {
521
+ prevAnimationNameRef.current = getAnimationName(stylesRef.current);
522
+ }
523
+ };
524
+ node.addEventListener("animationstart", handleAnimationStart);
525
+ node.addEventListener("animationcancel", handleAnimationEnd);
526
+ node.addEventListener("animationend", handleAnimationEnd);
527
+ return () => {
528
+ ownerWindow.clearTimeout(timeoutId);
529
+ node.removeEventListener("animationstart", handleAnimationStart);
530
+ node.removeEventListener("animationcancel", handleAnimationEnd);
531
+ node.removeEventListener("animationend", handleAnimationEnd);
532
+ };
533
+ } else {
534
+ send("ANIMATION_END");
535
+ }
536
+ }, [node, send]);
537
+ return {
538
+ isPresent: ["mounted", "unmountSuspended"].includes(state),
539
+ ref: React24.useCallback((node2) => {
540
+ stylesRef.current = node2 ? getComputedStyle(node2) : null;
541
+ setNode(node2);
542
+ }, [])
543
+ };
544
+ }
545
+ function getAnimationName(styles) {
546
+ return styles?.animationName || "none";
547
+ }
548
+ function getElementRef2(element) {
549
+ let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
550
+ let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
551
+ if (mayWarn) {
552
+ return element.ref;
553
+ }
554
+ getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
555
+ mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
556
+ if (mayWarn) {
557
+ return element.props.ref;
558
+ }
559
+ return element.props.ref || element.ref;
560
+ }
561
+
562
+ // node_modules/@radix-ui/react-id/dist/index.mjs
563
+ var React9 = __toESM(require("react"), 1);
564
+ var useReactId = React9[" useId ".trim().toString()] || (() => void 0);
565
+ var count = 0;
566
+ function useId(deterministicId) {
567
+ const [id, setId] = React9.useState(useReactId());
568
+ useLayoutEffect2(() => {
569
+ if (!deterministicId) setId((reactId) => reactId ?? String(count++));
570
+ }, [deterministicId]);
571
+ return deterministicId || (id ? `radix-${id}` : "");
572
+ }
573
+
574
+ // node_modules/@radix-ui/react-collapsible/dist/index.mjs
575
+ var import_jsx_runtime6 = require("react/jsx-runtime");
576
+ var COLLAPSIBLE_NAME = "Collapsible";
577
+ var [createCollapsibleContext, createCollapsibleScope] = createContextScope(COLLAPSIBLE_NAME);
578
+ var [CollapsibleProvider, useCollapsibleContext] = createCollapsibleContext(COLLAPSIBLE_NAME);
579
+ var Collapsible = React10.forwardRef(
580
+ (props, forwardedRef) => {
581
+ const {
582
+ __scopeCollapsible,
583
+ open: openProp,
584
+ defaultOpen,
585
+ disabled,
586
+ onOpenChange,
587
+ ...collapsibleProps
588
+ } = props;
589
+ const [open, setOpen] = useControllableState({
590
+ prop: openProp,
591
+ defaultProp: defaultOpen ?? false,
592
+ onChange: onOpenChange,
593
+ caller: COLLAPSIBLE_NAME
594
+ });
595
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
596
+ CollapsibleProvider,
597
+ {
598
+ scope: __scopeCollapsible,
599
+ disabled,
600
+ contentId: useId(),
601
+ open,
602
+ onOpenToggle: React10.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
603
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
604
+ Primitive.div,
605
+ {
606
+ "data-state": getState(open),
607
+ "data-disabled": disabled ? "" : void 0,
608
+ ...collapsibleProps,
609
+ ref: forwardedRef
610
+ }
611
+ )
612
+ }
613
+ );
614
+ }
615
+ );
616
+ Collapsible.displayName = COLLAPSIBLE_NAME;
617
+ var TRIGGER_NAME = "CollapsibleTrigger";
618
+ var CollapsibleTrigger = React10.forwardRef(
619
+ (props, forwardedRef) => {
620
+ const { __scopeCollapsible, ...triggerProps } = props;
621
+ const context = useCollapsibleContext(TRIGGER_NAME, __scopeCollapsible);
622
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
623
+ Primitive.button,
624
+ {
625
+ type: "button",
626
+ "aria-controls": context.contentId,
627
+ "aria-expanded": context.open || false,
628
+ "data-state": getState(context.open),
629
+ "data-disabled": context.disabled ? "" : void 0,
630
+ disabled: context.disabled,
631
+ ...triggerProps,
632
+ ref: forwardedRef,
633
+ onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
634
+ }
635
+ );
636
+ }
637
+ );
638
+ CollapsibleTrigger.displayName = TRIGGER_NAME;
639
+ var CONTENT_NAME = "CollapsibleContent";
640
+ var CollapsibleContent = React10.forwardRef(
641
+ (props, forwardedRef) => {
642
+ const { forceMount, ...contentProps } = props;
643
+ const context = useCollapsibleContext(CONTENT_NAME, props.__scopeCollapsible);
644
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Presence, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
645
+ }
646
+ );
647
+ CollapsibleContent.displayName = CONTENT_NAME;
648
+ var CollapsibleContentImpl = React10.forwardRef((props, forwardedRef) => {
649
+ const { __scopeCollapsible, present, children, ...contentProps } = props;
650
+ const context = useCollapsibleContext(CONTENT_NAME, __scopeCollapsible);
651
+ const [isPresent, setIsPresent] = React10.useState(present);
652
+ const ref = React10.useRef(null);
653
+ const composedRefs = useComposedRefs(forwardedRef, ref);
654
+ const heightRef = React10.useRef(0);
655
+ const height = heightRef.current;
656
+ const widthRef = React10.useRef(0);
657
+ const width = widthRef.current;
658
+ const isOpen = context.open || isPresent;
659
+ const isMountAnimationPreventedRef = React10.useRef(isOpen);
660
+ const originalStylesRef = React10.useRef(void 0);
661
+ React10.useEffect(() => {
662
+ const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);
663
+ return () => cancelAnimationFrame(rAF);
664
+ }, []);
665
+ useLayoutEffect2(() => {
666
+ const node = ref.current;
667
+ if (node) {
668
+ originalStylesRef.current = originalStylesRef.current || {
669
+ transitionDuration: node.style.transitionDuration,
670
+ animationName: node.style.animationName
671
+ };
672
+ node.style.transitionDuration = "0s";
673
+ node.style.animationName = "none";
674
+ const rect = node.getBoundingClientRect();
675
+ heightRef.current = rect.height;
676
+ widthRef.current = rect.width;
677
+ if (!isMountAnimationPreventedRef.current) {
678
+ node.style.transitionDuration = originalStylesRef.current.transitionDuration;
679
+ node.style.animationName = originalStylesRef.current.animationName;
680
+ }
681
+ setIsPresent(present);
682
+ }
683
+ }, [context.open, present]);
684
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
685
+ Primitive.div,
686
+ {
687
+ "data-state": getState(context.open),
688
+ "data-disabled": context.disabled ? "" : void 0,
689
+ id: context.contentId,
690
+ hidden: !isOpen,
691
+ ...contentProps,
692
+ ref: composedRefs,
693
+ style: {
694
+ [`--radix-collapsible-content-height`]: height ? `${height}px` : void 0,
695
+ [`--radix-collapsible-content-width`]: width ? `${width}px` : void 0,
696
+ ...props.style
697
+ },
698
+ children: isOpen && children
699
+ }
700
+ );
701
+ });
702
+ function getState(open) {
703
+ return open ? "open" : "closed";
704
+ }
705
+ var Root = Collapsible;
706
+ var Trigger = CollapsibleTrigger;
707
+ var Content = CollapsibleContent;
708
+
709
+ // node_modules/@radix-ui/react-direction/dist/index.mjs
710
+ var React11 = __toESM(require("react"), 1);
711
+ var import_jsx_runtime7 = require("react/jsx-runtime");
712
+ var DirectionContext = React11.createContext(void 0);
713
+ function useDirection(localDir) {
714
+ const globalDir = React11.useContext(DirectionContext);
715
+ return localDir || globalDir || "ltr";
716
+ }
717
+
718
+ // node_modules/@radix-ui/react-accordion/dist/index.mjs
719
+ var import_jsx_runtime8 = require("react/jsx-runtime");
720
+ var ACCORDION_NAME = "Accordion";
721
+ var ACCORDION_KEYS = ["Home", "End", "ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"];
722
+ var [Collection, useCollection, createCollectionScope] = createCollection(ACCORDION_NAME);
723
+ var [createAccordionContext, createAccordionScope] = createContextScope(ACCORDION_NAME, [
724
+ createCollectionScope,
725
+ createCollapsibleScope
726
+ ]);
727
+ var useCollapsibleScope = createCollapsibleScope();
728
+ var Accordion = import_react3.default.forwardRef(
729
+ (props, forwardedRef) => {
730
+ const { type, ...accordionProps } = props;
731
+ const singleProps = accordionProps;
732
+ const multipleProps = accordionProps;
733
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Collection.Provider, { scope: props.__scopeAccordion, children: type === "multiple" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionImplMultiple, { ...multipleProps, ref: forwardedRef }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionImplSingle, { ...singleProps, ref: forwardedRef }) });
734
+ }
735
+ );
736
+ Accordion.displayName = ACCORDION_NAME;
737
+ var [AccordionValueProvider, useAccordionValueContext] = createAccordionContext(ACCORDION_NAME);
738
+ var [AccordionCollapsibleProvider, useAccordionCollapsibleContext] = createAccordionContext(
739
+ ACCORDION_NAME,
740
+ { collapsible: false }
741
+ );
742
+ var AccordionImplSingle = import_react3.default.forwardRef(
743
+ (props, forwardedRef) => {
744
+ const {
745
+ value: valueProp,
746
+ defaultValue,
747
+ onValueChange = () => {
748
+ },
749
+ collapsible = false,
750
+ ...accordionSingleProps
751
+ } = props;
752
+ const [value, setValue] = useControllableState({
753
+ prop: valueProp,
754
+ defaultProp: defaultValue ?? "",
755
+ onChange: onValueChange,
756
+ caller: ACCORDION_NAME
757
+ });
758
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
759
+ AccordionValueProvider,
760
+ {
761
+ scope: props.__scopeAccordion,
762
+ value: import_react3.default.useMemo(() => value ? [value] : [], [value]),
763
+ onItemOpen: setValue,
764
+ onItemClose: import_react3.default.useCallback(() => collapsible && setValue(""), [collapsible, setValue]),
765
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionCollapsibleProvider, { scope: props.__scopeAccordion, collapsible, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionImpl, { ...accordionSingleProps, ref: forwardedRef }) })
766
+ }
767
+ );
768
+ }
769
+ );
770
+ var AccordionImplMultiple = import_react3.default.forwardRef((props, forwardedRef) => {
771
+ const {
772
+ value: valueProp,
773
+ defaultValue,
774
+ onValueChange = () => {
775
+ },
776
+ ...accordionMultipleProps
777
+ } = props;
778
+ const [value, setValue] = useControllableState({
779
+ prop: valueProp,
780
+ defaultProp: defaultValue ?? [],
781
+ onChange: onValueChange,
782
+ caller: ACCORDION_NAME
783
+ });
784
+ const handleItemOpen = import_react3.default.useCallback(
785
+ (itemValue) => setValue((prevValue = []) => [...prevValue, itemValue]),
786
+ [setValue]
787
+ );
788
+ const handleItemClose = import_react3.default.useCallback(
789
+ (itemValue) => setValue((prevValue = []) => prevValue.filter((value2) => value2 !== itemValue)),
790
+ [setValue]
791
+ );
792
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
793
+ AccordionValueProvider,
794
+ {
795
+ scope: props.__scopeAccordion,
796
+ value,
797
+ onItemOpen: handleItemOpen,
798
+ onItemClose: handleItemClose,
799
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionCollapsibleProvider, { scope: props.__scopeAccordion, collapsible: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AccordionImpl, { ...accordionMultipleProps, ref: forwardedRef }) })
800
+ }
801
+ );
802
+ });
803
+ var [AccordionImplProvider, useAccordionContext] = createAccordionContext(ACCORDION_NAME);
804
+ var AccordionImpl = import_react3.default.forwardRef(
805
+ (props, forwardedRef) => {
806
+ const { __scopeAccordion, disabled, dir, orientation = "vertical", ...accordionProps } = props;
807
+ const accordionRef = import_react3.default.useRef(null);
808
+ const composedRefs = useComposedRefs(accordionRef, forwardedRef);
809
+ const getItems = useCollection(__scopeAccordion);
810
+ const direction = useDirection(dir);
811
+ const isDirectionLTR = direction === "ltr";
812
+ const handleKeyDown = composeEventHandlers(props.onKeyDown, (event) => {
813
+ if (!ACCORDION_KEYS.includes(event.key)) return;
814
+ const target = event.target;
815
+ const triggerCollection = getItems().filter((item) => !item.ref.current?.disabled);
816
+ const triggerIndex = triggerCollection.findIndex((item) => item.ref.current === target);
817
+ const triggerCount = triggerCollection.length;
818
+ if (triggerIndex === -1) return;
819
+ event.preventDefault();
820
+ let nextIndex = triggerIndex;
821
+ const homeIndex = 0;
822
+ const endIndex = triggerCount - 1;
823
+ const moveNext = () => {
824
+ nextIndex = triggerIndex + 1;
825
+ if (nextIndex > endIndex) {
826
+ nextIndex = homeIndex;
827
+ }
828
+ };
829
+ const movePrev = () => {
830
+ nextIndex = triggerIndex - 1;
831
+ if (nextIndex < homeIndex) {
832
+ nextIndex = endIndex;
833
+ }
834
+ };
835
+ switch (event.key) {
836
+ case "Home":
837
+ nextIndex = homeIndex;
838
+ break;
839
+ case "End":
840
+ nextIndex = endIndex;
841
+ break;
842
+ case "ArrowRight":
843
+ if (orientation === "horizontal") {
844
+ if (isDirectionLTR) {
845
+ moveNext();
846
+ } else {
847
+ movePrev();
848
+ }
849
+ }
850
+ break;
851
+ case "ArrowDown":
852
+ if (orientation === "vertical") {
853
+ moveNext();
854
+ }
855
+ break;
856
+ case "ArrowLeft":
857
+ if (orientation === "horizontal") {
858
+ if (isDirectionLTR) {
859
+ movePrev();
860
+ } else {
861
+ moveNext();
862
+ }
863
+ }
864
+ break;
865
+ case "ArrowUp":
866
+ if (orientation === "vertical") {
867
+ movePrev();
868
+ }
869
+ break;
870
+ }
871
+ const clampedIndex = nextIndex % triggerCount;
872
+ triggerCollection[clampedIndex].ref.current?.focus();
873
+ });
874
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
875
+ AccordionImplProvider,
876
+ {
877
+ scope: __scopeAccordion,
878
+ disabled,
879
+ direction: dir,
880
+ orientation,
881
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Collection.Slot, { scope: __scopeAccordion, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
882
+ Primitive.div,
883
+ {
884
+ ...accordionProps,
885
+ "data-orientation": orientation,
886
+ ref: composedRefs,
887
+ onKeyDown: disabled ? void 0 : handleKeyDown
888
+ }
889
+ ) })
890
+ }
891
+ );
892
+ }
893
+ );
894
+ var ITEM_NAME = "AccordionItem";
895
+ var [AccordionItemProvider, useAccordionItemContext] = createAccordionContext(ITEM_NAME);
896
+ var AccordionItem = import_react3.default.forwardRef(
897
+ (props, forwardedRef) => {
898
+ const { __scopeAccordion, value, ...accordionItemProps } = props;
899
+ const accordionContext = useAccordionContext(ITEM_NAME, __scopeAccordion);
900
+ const valueContext = useAccordionValueContext(ITEM_NAME, __scopeAccordion);
901
+ const collapsibleScope = useCollapsibleScope(__scopeAccordion);
902
+ const triggerId = useId();
903
+ const open = value && valueContext.value.includes(value) || false;
904
+ const disabled = accordionContext.disabled || props.disabled;
905
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
906
+ AccordionItemProvider,
907
+ {
908
+ scope: __scopeAccordion,
909
+ open,
910
+ disabled,
911
+ triggerId,
912
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
913
+ Root,
914
+ {
915
+ "data-orientation": accordionContext.orientation,
916
+ "data-state": getState2(open),
917
+ ...collapsibleScope,
918
+ ...accordionItemProps,
919
+ ref: forwardedRef,
920
+ disabled,
921
+ open,
922
+ onOpenChange: (open2) => {
923
+ if (open2) {
924
+ valueContext.onItemOpen(value);
925
+ } else {
926
+ valueContext.onItemClose(value);
927
+ }
928
+ }
929
+ }
930
+ )
931
+ }
932
+ );
933
+ }
934
+ );
935
+ AccordionItem.displayName = ITEM_NAME;
936
+ var HEADER_NAME = "AccordionHeader";
937
+ var AccordionHeader = import_react3.default.forwardRef(
938
+ (props, forwardedRef) => {
939
+ const { __scopeAccordion, ...headerProps } = props;
940
+ const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
941
+ const itemContext = useAccordionItemContext(HEADER_NAME, __scopeAccordion);
942
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
943
+ Primitive.h3,
944
+ {
945
+ "data-orientation": accordionContext.orientation,
946
+ "data-state": getState2(itemContext.open),
947
+ "data-disabled": itemContext.disabled ? "" : void 0,
948
+ ...headerProps,
949
+ ref: forwardedRef
950
+ }
951
+ );
952
+ }
953
+ );
954
+ AccordionHeader.displayName = HEADER_NAME;
955
+ var TRIGGER_NAME2 = "AccordionTrigger";
956
+ var AccordionTrigger = import_react3.default.forwardRef(
957
+ (props, forwardedRef) => {
958
+ const { __scopeAccordion, ...triggerProps } = props;
959
+ const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
960
+ const itemContext = useAccordionItemContext(TRIGGER_NAME2, __scopeAccordion);
961
+ const collapsibleContext = useAccordionCollapsibleContext(TRIGGER_NAME2, __scopeAccordion);
962
+ const collapsibleScope = useCollapsibleScope(__scopeAccordion);
963
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Collection.ItemSlot, { scope: __scopeAccordion, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
964
+ Trigger,
965
+ {
966
+ "aria-disabled": itemContext.open && !collapsibleContext.collapsible || void 0,
967
+ "data-orientation": accordionContext.orientation,
968
+ id: itemContext.triggerId,
969
+ ...collapsibleScope,
970
+ ...triggerProps,
971
+ ref: forwardedRef
972
+ }
973
+ ) });
974
+ }
975
+ );
976
+ AccordionTrigger.displayName = TRIGGER_NAME2;
977
+ var CONTENT_NAME2 = "AccordionContent";
978
+ var AccordionContent = import_react3.default.forwardRef(
979
+ (props, forwardedRef) => {
980
+ const { __scopeAccordion, ...contentProps } = props;
981
+ const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
982
+ const itemContext = useAccordionItemContext(CONTENT_NAME2, __scopeAccordion);
983
+ const collapsibleScope = useCollapsibleScope(__scopeAccordion);
984
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
985
+ Content,
986
+ {
987
+ role: "region",
988
+ "aria-labelledby": itemContext.triggerId,
989
+ "data-orientation": accordionContext.orientation,
990
+ ...collapsibleScope,
991
+ ...contentProps,
992
+ ref: forwardedRef,
993
+ style: {
994
+ ["--radix-accordion-content-height"]: "var(--radix-collapsible-content-height)",
995
+ ["--radix-accordion-content-width"]: "var(--radix-collapsible-content-width)",
996
+ ...props.style
997
+ }
998
+ }
999
+ );
1000
+ }
1001
+ );
1002
+ AccordionContent.displayName = CONTENT_NAME2;
1003
+ function getState2(open) {
1004
+ return open ? "open" : "closed";
1005
+ }
1006
+ var Root2 = Accordion;
1007
+ var Item = AccordionItem;
1008
+ var Header = AccordionHeader;
1009
+ var Trigger2 = AccordionTrigger;
1010
+ var Content2 = AccordionContent;
49
1011
 
50
1012
  // src/store.ts
51
- var import_react = require("react");
1013
+ var import_react4 = require("react");
52
1014
  var ConcertinaStore = class {
53
1015
  constructor() {
54
1016
  this._value = "";
55
- this._switching = false;
56
1017
  this._itemRefs = {};
57
1018
  this._listeners = /* @__PURE__ */ new Set();
58
1019
  this.subscribe = (listener) => {
@@ -60,22 +1021,14 @@ var ConcertinaStore = class {
60
1021
  return () => this._listeners.delete(listener);
61
1022
  };
62
1023
  this.getValue = () => this._value;
63
- this.getSwitching = () => this._switching;
64
1024
  }
65
1025
  _notify() {
66
1026
  for (const listener of this._listeners) listener();
67
1027
  }
68
1028
  setValue(newValue) {
69
- const wasSwitching = !!this._value && this._value !== newValue && !!newValue;
70
- this._switching = wasSwitching;
71
1029
  this._value = newValue || "";
72
1030
  this._notify();
73
1031
  }
74
- clearSwitching() {
75
- if (!this._switching) return;
76
- this._switching = false;
77
- this._notify();
78
- }
79
1032
  getItemRef(id) {
80
1033
  return this._itemRefs[id] ?? null;
81
1034
  }
@@ -83,7 +1036,7 @@ var ConcertinaStore = class {
83
1036
  this._itemRefs[id] = el;
84
1037
  }
85
1038
  };
86
- var ConcertinaContext = (0, import_react.createContext)(null);
1039
+ var ConcertinaContext = (0, import_react4.createContext)(null);
87
1040
 
88
1041
  // src/pin-to-scroll-top.ts
89
1042
  function pinToScrollTop(el) {
@@ -115,45 +1068,53 @@ function pinToScrollTop(el) {
115
1068
  }
116
1069
  }
117
1070
 
1071
+ // src/use-transition-lock.ts
1072
+ var import_react5 = require("react");
1073
+ function useTransitionLock() {
1074
+ const [locked, setLocked] = (0, import_react5.useState)(false);
1075
+ const lock = (0, import_react5.useCallback)(() => setLocked(true), []);
1076
+ (0, import_react5.useEffect)(() => {
1077
+ if (locked) setLocked(false);
1078
+ }, [locked]);
1079
+ return { locked, lock };
1080
+ }
1081
+
118
1082
  // src/root.tsx
119
- var import_jsx_runtime = require("react/jsx-runtime");
120
- var Root2 = (0, import_react2.forwardRef)(
121
- function Root3({ collapsible = true, children, ...props }, forwardedRef) {
122
- const storeRef = (0, import_react2.useRef)(null);
1083
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1084
+ var Root3 = (0, import_react6.forwardRef)(
1085
+ function Root4({ collapsible = true, children, ...props }, forwardedRef) {
1086
+ const storeRef = (0, import_react6.useRef)(null);
123
1087
  if (!storeRef.current) {
124
1088
  storeRef.current = new ConcertinaStore();
125
1089
  }
126
1090
  const store = storeRef.current;
127
- const value = (0, import_react2.useSyncExternalStore)(
1091
+ const value = (0, import_react6.useSyncExternalStore)(
128
1092
  store.subscribe,
129
1093
  store.getValue,
130
1094
  store.getValue
131
1095
  );
132
- const switching = (0, import_react2.useSyncExternalStore)(
133
- store.subscribe,
134
- store.getSwitching,
135
- store.getSwitching
136
- );
137
- const onValueChange = (0, import_react2.useCallback)(
138
- (newValue) => store.setValue(newValue),
139
- [store]
1096
+ const { locked, lock } = useTransitionLock();
1097
+ const onValueChange = (0, import_react6.useCallback)(
1098
+ (newValue) => {
1099
+ const isSwitching = !!store.getValue() && store.getValue() !== newValue && !!newValue;
1100
+ if (isSwitching) lock();
1101
+ store.setValue(newValue);
1102
+ },
1103
+ [store, lock]
140
1104
  );
141
- (0, import_react2.useLayoutEffect)(() => {
1105
+ (0, import_react6.useLayoutEffect)(() => {
142
1106
  if (!value) return;
143
1107
  pinToScrollTop(store.getItemRef(value));
144
1108
  }, [value, store]);
145
- (0, import_react2.useEffect)(() => {
146
- if (switching) store.clearSwitching();
147
- }, [switching, store]);
148
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConcertinaContext.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
149
- Accordion.Root,
1109
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConcertinaContext.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1110
+ Root2,
150
1111
  {
151
1112
  ref: forwardedRef,
152
1113
  type: "single",
153
1114
  collapsible,
154
1115
  value,
155
1116
  onValueChange,
156
- "data-switching": switching || void 0,
1117
+ "data-switching": locked || void 0,
157
1118
  ...props,
158
1119
  children
159
1120
  }
@@ -162,12 +1123,11 @@ var Root2 = (0, import_react2.forwardRef)(
162
1123
  );
163
1124
 
164
1125
  // src/item.tsx
165
- var import_react3 = require("react");
166
- var Accordion2 = __toESM(require("@radix-ui/react-accordion"), 1);
167
- var import_jsx_runtime2 = require("react/jsx-runtime");
168
- var Item2 = (0, import_react3.forwardRef)(function Item3({ value, ...props }, forwardedRef) {
169
- const store = (0, import_react3.useContext)(ConcertinaContext);
170
- const mergedRef = (0, import_react3.useCallback)(
1126
+ var import_react7 = require("react");
1127
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1128
+ var Item2 = (0, import_react7.forwardRef)(function Item3({ value, ...props }, forwardedRef) {
1129
+ const store = (0, import_react7.useContext)(ConcertinaContext);
1130
+ const mergedRef = (0, import_react7.useCallback)(
171
1131
  (el) => {
172
1132
  if (typeof forwardedRef === "function") {
173
1133
  forwardedRef(el);
@@ -178,22 +1138,21 @@ var Item2 = (0, import_react3.forwardRef)(function Item3({ value, ...props }, fo
178
1138
  },
179
1139
  [forwardedRef, store, value]
180
1140
  );
181
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Accordion2.Item, { ref: mergedRef, value, ...props });
1141
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Item, { ref: mergedRef, value, ...props });
182
1142
  });
183
1143
 
184
1144
  // src/content.tsx
185
- var import_react4 = require("react");
186
- var Accordion3 = __toESM(require("@radix-ui/react-accordion"), 1);
187
- var import_jsx_runtime3 = require("react/jsx-runtime");
188
- var Content2 = (0, import_react4.forwardRef)(function Content3({ className, ...props }, ref) {
1145
+ var import_react8 = require("react");
1146
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1147
+ var Content3 = (0, import_react8.forwardRef)(function Content4({ className, ...props }, ref) {
189
1148
  const merged = className ? `concertina-content ${className}` : "concertina-content";
190
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Accordion3.Content, { ref, className: merged, ...props });
1149
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Content2, { ref, className: merged, ...props });
191
1150
  });
192
1151
 
193
1152
  // src/use-expanded.ts
194
- var import_react5 = require("react");
1153
+ var import_react9 = require("react");
195
1154
  function useStore() {
196
- const store = (0, import_react5.useContext)(ConcertinaContext);
1155
+ const store = (0, import_react9.useContext)(ConcertinaContext);
197
1156
  if (!store) {
198
1157
  throw new Error("useExpanded must be used inside <Concertina.Root>");
199
1158
  }
@@ -201,7 +1160,7 @@ function useStore() {
201
1160
  }
202
1161
  function useExpanded(id) {
203
1162
  const store = useStore();
204
- return (0, import_react5.useSyncExternalStore)(
1163
+ return (0, import_react9.useSyncExternalStore)(
205
1164
  store.subscribe,
206
1165
  () => store.getValue() === id,
207
1166
  () => false
@@ -209,16 +1168,106 @@ function useExpanded(id) {
209
1168
  );
210
1169
  }
211
1170
 
212
- // src/index.ts
213
- var import_react_accordion = require("@radix-ui/react-accordion");
1171
+ // src/stable-slot.tsx
1172
+ var import_react10 = require("react");
1173
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1174
+ var AxisContext = (0, import_react10.createContext)("both");
1175
+ var StableSlot = (0, import_react10.forwardRef)(
1176
+ function StableSlot2({ axis = "both", className, children, ...props }, ref) {
1177
+ const merged = className ? `concertina-stable-slot ${className}` : "concertina-stable-slot";
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AxisContext.Provider, { value: axis, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref, className: merged, ...props, children }) });
1179
+ }
1180
+ );
1181
+
1182
+ // src/slot.tsx
1183
+ var import_react11 = require("react");
1184
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1185
+ function inactiveStyle(axis) {
1186
+ const base = { visibility: "hidden", overflow: "hidden" };
1187
+ if (axis === "width") {
1188
+ base.maxHeight = 0;
1189
+ } else if (axis === "height") {
1190
+ base.maxWidth = 0;
1191
+ }
1192
+ return base;
1193
+ }
1194
+ var Slot = (0, import_react11.forwardRef)(
1195
+ function Slot2({ active, style, children, ...props }, ref) {
1196
+ const axis = (0, import_react11.useContext)(AxisContext);
1197
+ const merged = active ? { ...style } : { ...inactiveStyle(axis), ...style };
1198
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1199
+ "div",
1200
+ {
1201
+ ref,
1202
+ inert: !active || void 0,
1203
+ style: merged,
1204
+ ...props,
1205
+ children
1206
+ }
1207
+ );
1208
+ }
1209
+ );
1210
+
1211
+ // src/use-stable-slot.ts
1212
+ var import_react12 = require("react");
1213
+ function useStableSlot(options = {}) {
1214
+ const { axis = "both" } = options;
1215
+ const [style, setStyle] = (0, import_react12.useState)({});
1216
+ const maxRef = (0, import_react12.useRef)({ w: 0, h: 0 });
1217
+ const observerRef = (0, import_react12.useRef)(null);
1218
+ const ref = (0, import_react12.useCallback)(
1219
+ (el) => {
1220
+ if (observerRef.current) {
1221
+ observerRef.current.disconnect();
1222
+ observerRef.current = null;
1223
+ }
1224
+ if (!el || typeof ResizeObserver === "undefined") return;
1225
+ const observer = new ResizeObserver((entries) => {
1226
+ for (const entry of entries) {
1227
+ let w;
1228
+ let h;
1229
+ if (entry.borderBoxSize?.length) {
1230
+ const box = entry.borderBoxSize[0];
1231
+ w = box.inlineSize;
1232
+ h = box.blockSize;
1233
+ } else {
1234
+ const rect = entry.target.getBoundingClientRect();
1235
+ w = rect.width;
1236
+ h = rect.height;
1237
+ }
1238
+ const max = maxRef.current;
1239
+ let grew = false;
1240
+ if ((axis === "width" || axis === "both") && w > max.w) {
1241
+ max.w = w;
1242
+ grew = true;
1243
+ }
1244
+ if ((axis === "height" || axis === "both") && h > max.h) {
1245
+ max.h = h;
1246
+ grew = true;
1247
+ }
1248
+ if (grew) {
1249
+ const next = {};
1250
+ if (axis === "width" || axis === "both") next.minWidth = max.w;
1251
+ if (axis === "height" || axis === "both") next.minHeight = max.h;
1252
+ setStyle(next);
1253
+ }
1254
+ }
1255
+ });
1256
+ observer.observe(el, { box: "border-box" });
1257
+ observerRef.current = observer;
1258
+ },
1259
+ [axis]
1260
+ );
1261
+ return { ref, style };
1262
+ }
214
1263
 
215
1264
  // src/use-concertina.ts
216
- var import_react6 = require("react");
1265
+ var import_react13 = require("react");
217
1266
  function useConcertina() {
218
- const [value, setValue] = (0, import_react6.useState)("");
219
- const [switching, setSwitching] = (0, import_react6.useState)(false);
220
- const itemRefs = (0, import_react6.useRef)({});
221
- const onValueChange = (0, import_react6.useCallback)(
1267
+ const [value, setValue] = (0, import_react13.useState)("");
1268
+ const [switching, setSwitching] = (0, import_react13.useState)(false);
1269
+ const itemRefs = (0, import_react13.useRef)({});
1270
+ const onValueChange = (0, import_react13.useCallback)(
222
1271
  (newValue) => {
223
1272
  if (!newValue) {
224
1273
  setSwitching(false);
@@ -230,14 +1279,14 @@ function useConcertina() {
230
1279
  },
231
1280
  [value]
232
1281
  );
233
- (0, import_react6.useLayoutEffect)(() => {
1282
+ (0, import_react13.useLayoutEffect)(() => {
234
1283
  if (!value) return;
235
1284
  pinToScrollTop(itemRefs.current[value]);
236
1285
  }, [value]);
237
- (0, import_react6.useEffect)(() => {
1286
+ (0, import_react13.useEffect)(() => {
238
1287
  if (switching) setSwitching(false);
239
1288
  }, [switching]);
240
- const getItemRef = (0, import_react6.useCallback)(
1289
+ const getItemRef = (0, import_react13.useCallback)(
241
1290
  (id) => (el) => {
242
1291
  itemRefs.current[id] = el;
243
1292
  },
@@ -258,8 +1307,12 @@ function useConcertina() {
258
1307
  Header,
259
1308
  Item,
260
1309
  Root,
1310
+ Slot,
1311
+ StableSlot,
261
1312
  Trigger,
262
1313
  pinToScrollTop,
263
1314
  useConcertina,
264
- useExpanded
1315
+ useExpanded,
1316
+ useStableSlot,
1317
+ useTransitionLock
265
1318
  });